<!DOCTYPE html><html class="theme-next gemini use-motion" lang="zh-Hans"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1"><meta name="theme-color" content="#222"><script src="//cdn.bootcss.com/pace/1.0.2/pace.min.js"></script><link href="//cdn.bootcss.com/pace/1.0.2/themes/pink/pace-theme-flash.css" rel="stylesheet"><style>.pace .pace-progress{background:#1e92fb;height:3px}.pace .pace-progress-inner{box-shadow:0 0 10px #1e92fb,0 0 5px #1e92fb}.pace .pace-activity{border-top-color:#1e92fb;border-left-color:#1e92fb}</style><meta http-equiv="Cache-Control" content="no-transform"><meta http-equiv="Cache-Control" content="no-siteapp"><link href="/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css"><link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css"><link href="/css/main.css?v=5.1.4" rel="stylesheet" type="text/css"><link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png?v=5.1.4"><link rel="icon" type="image/png" sizes="32x32" href="/images/favicon.ico?v=5.1.4"><link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png?v=5.1.4"><link rel="mask-icon" href="/images/logo.svg?v=5.1.4" color="#222"><meta name="keywords" content="数据结构与算法,"><link rel="alternate" href="/atom.xml" title="It is written" type="application/atom+xml"><meta name="description" content="数据结构：数据的组织、管理、存储的结构，好的数据结构可以提高代码效率。 分为三类：  线性结构（一对一） 树结构（一对多） 图结构（多对多）"><meta property="og:type" content="article"><meta property="og:title" content="数据结构与算法 (js版)  -- 数据结构"><meta property="og:url" content="http://king-xiyu.gitee.io/article/2a16eda9.html"><meta property="og:site_name" content="It is written"><meta property="og:description" content="数据结构：数据的组织、管理、存储的结构，好的数据结构可以提高代码效率。 分为三类：  线性结构（一对一） 树结构（一对多） 图结构（多对多）"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1ges3rlq68pj3176086qks.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1ges3vwjidkj316q0gkdsw.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1ges458oev2j316q06ewfw.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1ges4d963b9j30co07e75h.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1ges4g2pd3ej316a03qt9k.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1ges4ghwx27j314e05aaaz.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1ges4guvjsdj315q03y3zr.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1ges4h50teuj311g05cabc.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gesa6anycqj30eg0cwgmy.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1getdvtnxqvj30nq068gmx.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gete4345atj30l60lyh2q.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1getecgvqfjj30w40fwqiu.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1getg336qvaj31760cm493.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1getg3ezl1rj317a0c8qdk.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1getg44qn1wj318k0bwqds.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1getg55iebpj317y0doakh.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1getjcmuy13j316e0qaqg4.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1getjeo76vlj31660n6k3h.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1getjf4nlepj31720t04p9.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1getjidjm13j313e0oytix.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1getjioahfuj30a606gjs5.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1getjixpfprj30ly0a477u.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1getjj9far6j30m40e27ed.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1getjjz3jc2j30l20fcgr1.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1getjl0r7f4j30q00jo12r.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1getjlrbpy8j30ou0g2dph.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1getjmaiheaj30jy0fgtfw.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gexxecabd6j30g8082di9.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gexxf1p9w2j30qg0me7g1.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gexxfoj2fgj30v40k8qdx.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gexxgclvsij30rs0nqwqy.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gexxgvrxjqj30ui0nods6.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1getjnz33njj317i08418k.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1getjoijytnj319w0eqx3a.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1getjoyy0msj30c608mwgc.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gewmdxea8uj308h0rmdgm.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1getjoyy0msj30c608mwgc.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gewmg85rijj30dt0a6t8x.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1getjqmbwggj30tc0lun79.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gewmj9588cj30xm0be0wn.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gewmkabs92j30g40i0abs.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gewmmxczoqj317g0amjut.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gewmngisfdj318q0cmwjf.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gewmoap911j31860dgn25.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gewmpok2irj316k0ag77n.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gewmpyotf4j318a0digqr.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gewmqmc49wj317y0dsq8f.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gewmrfp9p5j318y090q5y.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gewms58df1j319m0akjvx.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gewmsen0rqj318q0ai78p.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gewmtleem9j317u08qad0.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gewmtupa1wj318o0a2dki.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gewmu4pa0mj318o0a0gqa.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gewn26h6fkj30lg0ae76l.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gewn3ktfs0j30ky09qq56.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gewn56fu5mj30m207s762.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gewn7jh7pcj30mk0760um.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gewnfticemj30bl0gc74r.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gexxl3mbctj30ti0jo7mf.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gexxu4h7etj30be08gmxx.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gexxujf9kcj30p00cqgoi.jpg"><meta property="og:image" content="https://img.kancloud.cn/36/7c/367c25251bdf4400bc285f53280b1b6e_1166x814.png"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gexxvwe8buj30ve0p8nb5.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gexxwedocoj30vc0ok7ie.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gexxwzncknj30w00oq4d0.jpg"><meta property="og:image" content="https://img.kancloud.cn/2e/51/2e51c02ed76614e2f7b1d980e87f8ea1_1140x910.png"><meta property="og:image" content="https://img.kancloud.cn/c3/97/c397773fae8ae6618c2a2561d9a8b5fa_1158x920.png"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gexxz8nzl2j30vg0pk16h.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gexxzuuiqbj30ve0pak57.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gexy2hlcg5j30v20powt2.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gexy3j0fy7j30kw0i2tes.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gexy45356nj30n209678c.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gexy4m0ai3j30se0mmn7l.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gey0mh1sylj30yc0u4h3f.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gey0n00x1nj30xs0twdym.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gey0njwevoj30yo0vc1bc.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gey0nx7lh9j30xw0vw7mo.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gey0oe05d6j30xm0h8wlu.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gey0ov2ji6j30dy0e23z3.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gey0ph84irj30hs0p4tdx.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gey0qv0kywj306o0pyjst.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gey0rdxiylj30k80rqq80.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gey0rvpbhrj30je0l2tcm.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gey0sm7en0j30m80ly449.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gey0t3vh63j30ma0k4n3o.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gey0tle9p5j30n40miwmi.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gey0trzj0yj30ma0kowlf.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gey0ug9eakj30qm0p8thh.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gey0uqsiaqj30ru0q2the.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gey0v56aj7j30xw0vmtk7.jpg"><meta property="og:image" content="https://img.kancloud.cn/0b/1f/0b1f9c52ef4b2e234cbc8b1c9923800f_1200x1156.png"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gez6f6743dj30xy0l2qct.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gez6fwzp4dj30y40x0aox.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gez6qbzpdmj30rc0astax.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gez6qvfh1oj30dm0d2god.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gez6sljf43j30gc0e6wg0.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gez6t8h9a9j30g00eagmx.jpg"><meta property="og:image" content="https://img.kancloud.cn/21/5a/215a4cd30410052072c6174eafc60c69_498x452.png"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gez6uh9jlbj310a0dagpo.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gez6xlhwfij30do0jy401.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gez6yq2c3oj30d40jygnc.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gez6zzespwj30ym0bq416.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gez73265mij30n4096q6u.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gez74qdks6j314m0f8gpr.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gez7bllf7gj316u0gk7g1.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gez7c55yorj318e138no0.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gf0e12p2rcj30e60cqdjo.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gf0e1easukj30eu0d4td1.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gf0e1of750j30ei0cmq76.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gf0e35ksumj30e80bw422.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gf0e3d94gkj30dg0bgn0q.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gf0e3m3o9oj30eo0ck0wp.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gf0e49ool2j30kc10o4as.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gf0e66cjywj30my0eith3.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gf0e73amalj30vu0jejxl.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gf0ekzk5f5j30lo13m16i.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gf0elohg2oj30ia0c8jx3.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gf0em51d7wj318q0u47p4.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gf0enomz0ej30kk0tcwse.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gf0eo5byoxj31ko0v84qp.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gf0eom4xuej3086072jtf.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gf0ep0laf0j30pm0zs1at.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gf0epqmd3dj31hy0o6b29.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gf0eqh4g4qj30so0zuh5t.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gf0eqx7h6uj31pm0n4hdt.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gf0erk39f1j30om0p8ao9.jpg"><meta property="og:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1gf0erzahdvj31ku0m41kx.jpg"><meta property="article:published_time" content="2020-05-14T09:13:39.000Z"><meta property="article:modified_time" content="2020-09-01T00:45:14.041Z"><meta property="article:author" content="King-XiYu"><meta property="article:tag" content="数据结构与算法"><meta name="twitter:card" content="summary"><meta name="twitter:image" content="http://ww1.sinaimg.cn/large/007WurYGgy1ges3rlq68pj3176086qks.jpg"><script type="text/javascript" id="hexo.configurations">var NexT=window.NexT||{},CONFIG={root:"/",scheme:"Gemini",version:"5.1.4",sidebar:{position:"left",display:"post",offset:12,b2t:!0,scrollpercent:!0,onmobile:!1},fancybox:!0,tabs:!0,motion:{enable:!0,async:!1,transition:{post_block:"fadeIn",post_header:"slideDownIn",post_body:"slideDownIn",coll_header:"slideLeftIn",sidebar:"slideUpIn"}},duoshuo:{userId:"0",author:"博主"},algolia:{applicationID:"",apiKey:"",indexName:"",hits:{per_page:10},labels:{input_placeholder:"Search for Posts",hits_empty:"We didn't find any results for the search: ${query}",hits_stats:"${hits} results found in ${time} ms"}}}</script><link rel="canonical" href="http://king-xiyu.gitee.io/article/2a16eda9.html"><title>数据结构与算法 (js版) -- 数据结构 | It is written</title><meta name="generator" content="Hexo 4.2.0"></head><body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans"><div class="container sidebar-position-left page-post-detail"><div class="headband"></div><header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader"><div class="header-inner"><div class="site-brand-wrapper"><div class="site-meta"><div class="custom-logo-site-title"><a href="/" class="brand" rel="start"><span class="logo-line-before"><i></i></span> <span class="site-title">It is written</span><span class="logo-line-after"><i></i></span></a></div><p class="site-subtitle"></p></div><div class="site-nav-toggle"> <button><span class="btn-bar"></span><span class="btn-bar"></span><span class="btn-bar"></span></button></div></div><nav class="site-nav"><ul id="menu" class="menu"><li class="menu-item menu-item-home"><a href="/" rel="section"><i class="menu-item-icon fa fa-fw fa-home"></i><br> 首页</a></li><li class="menu-item menu-item-tags"><a href="/tags/" rel="section"><i class="menu-item-icon fa fa-fw fa-tags"></i><br> 标签</a></li><li class="menu-item menu-item-categories"><a href="/categories/" rel="section"><i class="menu-item-icon fa fa-fw fa-th"></i><br> 分类</a></li><li class="menu-item menu-item-archives"><a href="/archives/" rel="section"><i class="menu-item-icon fa fa-fw fa-archive"></i><br> 归档</a></li><li class="menu-item menu-item-about"><a href="/about/" rel="section"><i class="menu-item-icon fa fa-fw fa-user"></i><br> 关于</a></li><li class="menu-item menu-item-search"><a href="javascript:;" class="popup-trigger"><i class="menu-item-icon fa fa-search fa-fw"></i><br> 搜索</a></li></ul><div class="site-search"><div class="popup search-popup local-search-popup"><div class="local-search-header clearfix"><span class="search-icon"><i class="fa fa-search"></i></span><span class="popup-btn-close"><i class="fa fa-times-circle"></i></span><div class="local-search-input-wrapper"> <input autocomplete="off" placeholder="搜索..." spellcheck="false" type="text" id="local-search-input"></div></div><div id="local-search-result"></div></div></div></nav></div></header><main id="main" class="main"><div class="main-inner"><div class="content-wrap"><div id="content" class="content"><div id="posts" class="posts-expand"><article class="post post-type-normal" itemscope itemtype="http://schema.org/Article"><div class="post-block"><link itemprop="mainEntityOfPage" href="http://king-xiyu.gitee.io/article/2a16eda9.html"><span hidden itemprop="author" itemscope itemtype="http://schema.org/Person"><meta itemprop="name" content="King-XiYu"><meta itemprop="description" content=""><meta itemprop="image" content="http://ww1.sinaimg.cn/large/007WurYGgy1ge8nxttd9nj302s02s0si.jpg"></span><span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization"><meta itemprop="name" content="It is written"></span><header class="post-header"><h1 class="post-title" itemprop="name headline">数据结构与算法 (js版) -- 数据结构</h1><div class="post-meta"><span class="post-time"><span class="post-meta-item-icon"><i class="fa fa-calendar-o"></i></span> <span class="post-meta-item-text">发表于</span> <time title="创建于" itemprop="dateCreated datePublished" datetime="2020-05-14T17:13:39+08:00">2020-05-14</time> <span class="post-meta-divider">|</span><span class="post-meta-item-icon"><i class="fa fa-calendar-check-o"></i></span> <span class="post-meta-item-text">更新于&#58;</span> <time title="更新于" itemprop="dateModified" datetime="2020-09-01T08:45:14+08:00">2020-09-01</time></span> <span class="post-category"><span class="post-meta-divider">|</span><span class="post-meta-item-icon"><i class="fa fa-folder-o"></i></span> <span class="post-meta-item-text">分类于</span> <span itemprop="about" itemscope itemtype="http://schema.org/Thing"><a href="/categories/%E6%8A%80%E6%9C%AF%E6%A0%88/" itemprop="url" rel="index"><span itemprop="name">技术栈</span></a></span> ， <span itemprop="about" itemscope itemtype="http://schema.org/Thing"><a href="/categories/%E6%8A%80%E6%9C%AF%E6%A0%88/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/" itemprop="url" rel="index"><span itemprop="name">数据结构与算法</span></a></span></span> <span class="post-comments-count"><span class="post-meta-divider">|</span><span class="post-meta-item-icon"><i class="fa fa-comment-o"></i></span><a href="/article/2a16eda9.html#comments" itemprop="discussionUrl"><span class="post-comments-count valine-comment-count" data-xid="/article/2a16eda9.html" itemprop="commentCount"></span></a></span> <span id="/article/2a16eda9.html" class="leancloud_visitors" data-flag-title="数据结构与算法 (js版)  -- 数据结构"><span class="post-meta-divider">|</span><span class="post-meta-item-icon"><i class="fa fa-eye"></i></span> <span class="post-meta-item-text">阅读次数&#58;</span><span class="leancloud-visitors-count"></span></span><div class="post-wordcount"><span class="post-meta-item-icon"><i class="fa fa-file-word-o"></i></span> <span class="post-meta-item-text">字数统计&#58;</span> <span title="字数统计">14.1k 字</span> <span class="post-meta-divider">|</span><span class="post-meta-item-icon"><i class="fa fa-clock-o"></i></span> <span class="post-meta-item-text">阅读时长 &asymp;</span> <span title="阅读时长">58 分钟</span></div></div></header><div class="post-body" itemprop="articleBody"><p>数据结构：数据的组织、管理、存储的结构，好的数据结构可以提高代码效率。</p><p>分为三类：</p><ul><li>线性结构（一对一）</li><li>树结构（一对多）</li><li>图结构（多对多）</li></ul><a id="more"></a><br><h1 id="线性结构"><a href="#线性结构" class="headerlink" title="线性结构"></a>线性结构</h1><p>线性结构：一对一的数据结构。</p><p>主要分为：</p><ul><li>数组</li><li>链表</li><li>栈</li><li>队列</li><li>散列表</li></ul><p>学习目标：</p><ol><li>能够说出每种数据结构的特点</li><li>能够使用代码实现每种数据结构以及相关操作</li></ol><br><h2 id="数组"><a href="#数组" class="headerlink" title="数组"></a>数组</h2><p>数组（Array）：它在内存中是 <code>连续</code> 、 <code>顺序</code> 存储的线性结构，通过下标来进行访问。</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1ges3rlq68pj3176086qks.jpg" alt="3198f3397983a35194a72208654f2a6c_1554x294.png"></p><p>特点：</p><p><code>高效</code> 的读取操作。 （通过下标直接访问）</p><p>比如： 获取第3个元素： arr[2]</p><p><code>低效</code> 的插入、删除操作。（因为数据是在内存中连续存储的，所以每当向其中插入一条记录时，后面的数据就都需要向后移动一个位置，同理，在删除一个数据时，后面的数据都需要向前移动一位）</p><p>比如：插入时所有元素要向后移动一位：</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1ges3vwjidkj316q0gkdsw.jpg" alt="fc8fc5aba8978aa38efded2e743c5cc4_1538x596.png"></p><p>JS 中已经有了数组这种数据结构，而且我们也一直在用，所有这里不再过多的介绍它的用法了。</p><br><h2 id="链表"><a href="#链表" class="headerlink" title="链表"></a>链表</h2><h3 id="介绍"><a href="#介绍" class="headerlink" title="介绍"></a>介绍</h3><h4 id="存储结构"><a href="#存储结构" class="headerlink" title="存储结构"></a>存储结构</h4><p>链表（Linked List）：是一种 <code>非连续</code> 、 <code>非顺序</code> 存储的线性结构。</p><p>链表由一个个的 <code>节点</code> 组成，每个节点在内存中 <code>位置是随机</code> 不确定的（并不是顺序的）。为了让节点之间有联系，在每个节点中都有一个指针指向下一个节点。</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1ges458oev2j316q06ewfw.jpg" alt="d3e97f945ee236abe9f0852d0ccd8739_1538x230.png"></p><h4 id="特点"><a href="#特点" class="headerlink" title="特点"></a>特点</h4><p><code>高效</code> 的插入、删除操作。 （只需要修改指针的反向即可，不需要移动数据）</p><p><code>低效</code> 的随机读取一个元素。（只为没有下标，所以我们必须通过链表头一个一个节点的向下查找想要的元素）</p><p>高效的插入：</p><p>添加新节点只需要：</p><ol><li>将上一个节点指向新节点</li><li>将新节点指向下一个节点</li></ol><p>图示：向两个红色节点中插入一个新蓝色节点</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1ges4d963b9j30co07e75h.jpg" alt="345d1a7ddd6bddf9b56da9e2cfb38de9_456x266.png"></p><h4 id="类型"><a href="#类型" class="headerlink" title="类型"></a>类型</h4><p>链表又可以分为：</p><ul><li>单向链表</li><li>双向链表</li><li>循环链表</li><li>双向循环链表</li></ul><p>单链表</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1ges4g2pd3ej316a03qt9k.jpg" alt="08a86e3a234cda7c380b3ea3a9321cd9_1522x134.png"></p><p>循环链表</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1ges4ghwx27j314e05aaaz.jpg" alt="05f6e4032428f4923cf2361384c18195_1454x190.png"></p><p>双向链表</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1ges4guvjsdj315q03y3zr.jpg" alt="3ed24ada31b98c8e497e88c555c92b94_1502x142.png"></p><p>双向循环链表</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1ges4h50teuj311g05cabc.jpg" alt="de6ab3e50b682cf9e2d6391d086885ab_1348x192.png"></p><h3 id="代码实现"><a href="#代码实现" class="headerlink" title="代码实现"></a>代码实现</h3><p>在 Js 语言中没有提供链表这种数据结构（Java 中提供了），所以当我们需要使用这种数据结构时，我们需要自己实现一套链表功能。</p><p>比较适合使用“面向对象”的方式来实现。</p><p>JS 中的面向对象有两种写法：</p><h4 id="写法一、传统的写法（使用-function-定义类）"><a href="#写法一、传统的写法（使用-function-定义类）" class="headerlink" title="写法一、传统的写法（使用 function 定义类）"></a>写法一、传统的写法（使用 function 定义类）</h4><p>定义类时两大原则：</p><ol><li>使用 function 来定义类</li><li>类中的方法定义在原型上（prototype）</li></ol><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 传统的 面向对象 （ES5之前）</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Node</span>(<span class="params">data</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">this</span>.data = data</span><br><span class="line">    <span class="keyword">this</span>.next = <span class="literal">null</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">LinkedList</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">this</span>.length = <span class="number">0</span> <span class="comment">// 链表中节点的数量</span></span><br><span class="line">    <span class="keyword">this</span>.head = <span class="literal">null</span> <span class="comment">// 链表的头节点</span></span><br><span class="line">    <span class="keyword">this</span>.tail = <span class="literal">null</span> <span class="comment">// 指向最后一个节点</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 传统的面向对象是把方法定义到原型上（prototype）</span></span><br><span class="line">LinkedList.prototype.append = <span class="function"><span class="keyword">function</span> (<span class="params">data</span>) </span>&#123;</span><br><span class="line">    <span class="comment">// 1. 先创建一个新节点</span></span><br><span class="line">    <span class="keyword">let</span> newNode = <span class="keyword">new</span> Node(data)</span><br><span class="line">    <span class="comment">// 2. 把这个新节点挂到链表的最后</span></span><br><span class="line">    <span class="comment">// 如果当前链表是空，那么这个新节点即是头节点，又是尾节点</span></span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">this</span>.tail === <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="keyword">this</span>.head = newNode</span><br><span class="line">        <span class="keyword">this</span>.tail = newNode</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="comment">// 让尾节点的 next 指向新节点（挂到最后）</span></span><br><span class="line">        <span class="keyword">this</span>.tail.next = newNode</span><br><span class="line">        <span class="comment">// 让 tail 指向这个新的节点（这个新节点现在是尾节点了）</span></span><br><span class="line">        <span class="keyword">this</span>.tail = <span class="keyword">this</span>.tail.next</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 链表长度+1</span></span><br><span class="line">    <span class="keyword">this</span>.length++</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 清除链表</span></span><br><span class="line">LinkedList.prototype.clear = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">this</span>.length = <span class="number">0</span></span><br><span class="line">    <span class="keyword">this</span>.head = <span class="literal">null</span></span><br><span class="line">    <span class="keyword">this</span>.tail = <span class="literal">null</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 删除第 index 个节点</span></span><br><span class="line">LinkedList.prototype.delete = <span class="function"><span class="keyword">function</span> (<span class="params">index</span>) </span>&#123;</span><br><span class="line">    <span class="comment">// 1. 先找到第 index-1 个节点（前一个节点）</span></span><br><span class="line">    <span class="keyword">let</span> prev = <span class="keyword">this</span>.getNodeByIndex(index - <span class="number">1</span>)</span><br><span class="line">    <span class="comment">// 2. 让它的前一个节点的 next 指向，当前这个节点的 next</span></span><br><span class="line">    prev.next = prev.next.next</span><br><span class="line">    <span class="comment">// 3. 长度-1</span></span><br><span class="line">    <span class="keyword">this</span>.length--</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 根据下标找一个节点</span></span><br><span class="line">LinkedList.prototype.getNodeByIndex = <span class="function"><span class="keyword">function</span> (<span class="params">index</span>) </span>&#123;</span><br><span class="line">    <span class="comment">// 要查找的下标是否在链表范围内</span></span><br><span class="line">    <span class="keyword">if</span> (index &gt; <span class="keyword">this</span>.length - <span class="number">1</span>) <span class="keyword">return</span> <span class="literal">null</span></span><br><span class="line">    <span class="comment">// 从头节点开始向后跳 index 次</span></span><br><span class="line">    <span class="keyword">let</span> current = <span class="keyword">this</span>.head  <span class="comment">// 头节点</span></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; index; i++) &#123;</span><br><span class="line">        <span class="comment">// 当前节点指向下一个节点</span></span><br><span class="line">        current = current.next</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> current</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 把链表转成一个字符串，打印时好查看</span></span><br><span class="line">LinkedList.prototype.toString = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">let</span> ret = <span class="string">''</span></span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">this</span>.length === <span class="number">0</span>) <span class="keyword">return</span> <span class="string">''</span></span><br><span class="line">    <span class="comment">// 取出第一个节点</span></span><br><span class="line">    <span class="keyword">let</span> current = <span class="keyword">this</span>.head</span><br><span class="line">    <span class="comment">// 把节点数据拼到字符串上</span></span><br><span class="line">    ret += current.data + <span class="string">'-&gt;'</span></span><br><span class="line">    <span class="comment">// 循环链表中所有的节点并输出</span></span><br><span class="line">    <span class="keyword">while</span> (current.next !== <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="comment">// 当前节点指向下一个节点</span></span><br><span class="line">        current = current.next</span><br><span class="line">        <span class="comment">// 取出节点上的数据拼到字符串上输出</span></span><br><span class="line">        ret += current.data + <span class="string">'-&gt;'</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> ret + <span class="string">'null'</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 创建一个链表</span></span><br><span class="line"><span class="keyword">const</span> lb = <span class="keyword">new</span> LinkedList()</span><br><span class="line"><span class="comment">// 向链表中追回几条记录</span></span><br><span class="line">lb.append(<span class="string">'a'</span>)</span><br><span class="line">lb.append(<span class="string">'b'</span>)</span><br><span class="line">lb.append(<span class="string">'c'</span>)</span><br><span class="line">lb.append(<span class="string">'d'</span>)</span><br><span class="line">lb.append(<span class="string">'hello'</span>)</span><br><span class="line">lb.append(<span class="string">'girl'</span>)</span><br><span class="line"><span class="comment">// 打印链表结构</span></span><br><span class="line"><span class="built_in">console</span>.log(lb.toString())</span><br><span class="line"></span><br><span class="line">lb.delete(<span class="number">4</span>) <span class="comment">// 删除第5个元素：hello</span></span><br><span class="line"><span class="built_in">console</span>.log(lb.toString())</span><br><span class="line"></span><br><span class="line">lb.clear()</span><br><span class="line"><span class="built_in">console</span>.log(lb.toString())</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">'结束'</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 结果如下</span></span><br><span class="line"><span class="comment">// a-&gt;b-&gt;c-&gt;d-&gt;hello-&gt;girl-&gt;null</span></span><br><span class="line"><span class="comment">// a-&gt;b-&gt;c-&gt;d-&gt;girl-&gt;null</span></span><br><span class="line"><span class="comment">// undefined</span></span><br><span class="line"><span class="comment">// 结束</span></span><br></pre></td></tr></table></figure><h4 id="写法二、ES6-中新语法-（使用-class-定义类）"><a href="#写法二、ES6-中新语法-（使用-class-定义类）" class="headerlink" title="写法二、ES6 中新语法 （使用 class 定义类）"></a>写法二、ES6 中新语法 （使用 class 定义类）</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// ES6 class定义类</span></span><br><span class="line"><span class="comment">// 定义一个节点类</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Node</span> </span>&#123;</span><br><span class="line">    <span class="keyword">constructor</span>(data) &#123;</span><br><span class="line">        <span class="keyword">this</span>.data = data</span><br><span class="line">        <span class="keyword">this</span>.next = <span class="literal">null</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 链表类（管理所有的节点）</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">LinkedList</span> </span>&#123;</span><br><span class="line">    <span class="keyword">constructor</span>() &#123;</span><br><span class="line">        <span class="keyword">this</span>.length = <span class="number">0</span>  <span class="comment">// 链表中节点的数量</span></span><br><span class="line">        <span class="keyword">this</span>.head = <span class="literal">null</span>  <span class="comment">// 链表的头节点</span></span><br><span class="line">        <span class="keyword">this</span>.tail = <span class="literal">null</span>     <span class="comment">// 指向最后一个节点</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 向链表的最后添加一个元素</span></span><br><span class="line">    append(data) &#123;</span><br><span class="line">        <span class="comment">// 1. 先创建一个新节点</span></span><br><span class="line">        <span class="keyword">let</span> newNode = <span class="keyword">new</span> Node(data)</span><br><span class="line">        <span class="comment">// 2. 把这个新节点挂到链表的最后</span></span><br><span class="line">        <span class="comment">// 如果当前链表是空，那么这个新节点即是头节点，又是尾节点</span></span><br><span class="line">        <span class="keyword">if</span> (<span class="keyword">this</span>.tail === <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">this</span>.head = newNode</span><br><span class="line">            <span class="keyword">this</span>.tail = newNode</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">// 让尾节点的 next 指向新节点（挂到最后）</span></span><br><span class="line">            <span class="keyword">this</span>.tail.next = newNode</span><br><span class="line">            <span class="comment">// 让tail指向指向这个新的节点（这个新节点现在是尾节点了）</span></span><br><span class="line">            <span class="keyword">this</span>.tail = <span class="keyword">this</span>.tail.next</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 链表长度+1</span></span><br><span class="line">        <span class="keyword">this</span>.length++</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 清除链表</span></span><br><span class="line">    clear() &#123;</span><br><span class="line">        <span class="keyword">this</span>.length = <span class="number">0</span></span><br><span class="line">        <span class="keyword">this</span>.head = <span class="literal">null</span></span><br><span class="line">        <span class="keyword">this</span>.tail = <span class="literal">null</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 删除第 index 个节点</span></span><br><span class="line">    <span class="keyword">delete</span>(index) &#123;</span><br><span class="line">        <span class="comment">// 1. 先找到第 index - 1 个节点（前一个节点）</span></span><br><span class="line">        <span class="keyword">let</span> prev = <span class="keyword">this</span>.getNodeByIndex(index - <span class="number">1</span>)</span><br><span class="line">        <span class="comment">// 2. 让它的前一个节点的 next 指向，当前这个节点的 next</span></span><br><span class="line">        prev.next = prev.next.next</span><br><span class="line">        <span class="comment">// 3. 长度-1</span></span><br><span class="line">        <span class="keyword">this</span>.length--</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 根据下标找一个节点</span></span><br><span class="line">    getNodeByIndex(index) &#123;</span><br><span class="line">        <span class="comment">// 要查找的下标是否在链表范围内</span></span><br><span class="line">        <span class="keyword">if</span> (index &gt; <span class="keyword">this</span>.length - <span class="number">1</span>) <span class="keyword">return</span> <span class="literal">null</span></span><br><span class="line">        <span class="comment">// 从头节点开始向后跳 index 次</span></span><br><span class="line">        <span class="keyword">let</span> current = <span class="keyword">this</span>.head  <span class="comment">// 头节点</span></span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; index; i++) &#123;</span><br><span class="line">            <span class="comment">// 当前节点指向下一个节点</span></span><br><span class="line">            current = current.next</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> current</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 把链表转成一个字符串，打印时看着好看</span></span><br><span class="line">    toString() &#123;</span><br><span class="line">        <span class="keyword">let</span> ret = <span class="string">''</span></span><br><span class="line">        <span class="keyword">if</span> (<span class="keyword">this</span>.length === <span class="number">0</span>) <span class="keyword">return</span> <span class="string">''</span></span><br><span class="line">        <span class="comment">// 取出第一个节点</span></span><br><span class="line">        <span class="keyword">let</span> current = <span class="keyword">this</span>.head</span><br><span class="line">        <span class="comment">// 把节点数据拼到字符串上</span></span><br><span class="line">        ret += current.data + <span class="string">'-&gt;'</span></span><br><span class="line">        <span class="comment">// 循环链表中所有的节点并输出</span></span><br><span class="line">        <span class="keyword">while</span> (current.next !== <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="comment">// 当前节点指向下一个节点</span></span><br><span class="line">            current = current.next</span><br><span class="line">            <span class="comment">// 取出节点上的数据拼到字符串上输出</span></span><br><span class="line">            ret += current.data + <span class="string">'-&gt;'</span></span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> ret + <span class="string">'null'</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 创建一个链表</span></span><br><span class="line"><span class="keyword">const</span> lb = <span class="keyword">new</span> LinkedList()</span><br><span class="line"><span class="comment">// 向链表中追回几条记录</span></span><br><span class="line">lb.append(<span class="string">'a'</span>)</span><br><span class="line">lb.append(<span class="string">'b'</span>)</span><br><span class="line">lb.append(<span class="string">'c'</span>)</span><br><span class="line">lb.append(<span class="string">'d'</span>)</span><br><span class="line">lb.append(<span class="string">'hello'</span>)</span><br><span class="line">lb.append(<span class="string">'boy'</span>)</span><br><span class="line"><span class="comment">// 打印链表结构</span></span><br><span class="line"><span class="built_in">console</span>.log(lb.toString())</span><br><span class="line">lb.delete(<span class="number">4</span>) <span class="comment">// 删除第5个元素：hello</span></span><br><span class="line"><span class="built_in">console</span>.log(lb.toString())</span><br></pre></td></tr></table></figure><p>运行结果:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 删除前：</span></span><br><span class="line">a-&gt;b-&gt;c-&gt;d-&gt;hello-&gt;boy-&gt;<span class="literal">null</span></span><br><span class="line"><span class="comment">// 删除后：</span></span><br><span class="line">a-&gt;b-&gt;c-&gt;d-&gt;boy-&gt;<span class="literal">null</span></span><br></pre></td></tr></table></figure><br><h2 id="栈"><a href="#栈" class="headerlink" title="栈"></a>栈</h2><h3 id="介绍-1"><a href="#介绍-1" class="headerlink" title="介绍"></a>介绍</h3><h4 id="特点-1"><a href="#特点-1" class="headerlink" title="特点"></a>特点</h4><p>栈 (Stack) 是一种 <code>后进先出</code> (英文: LIFO: Last In First Out) 的线性数据结构,并且只能 <code>从一头</code> 进出.</p><p>栈主要有两个操作:</p><p>入栈: 将数据放到栈顶</p><p>出栈: 将栈顶数据弹出栈,栈顶向下移动一位</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gesa6anycqj30eg0cwgmy.jpg" alt="faa3d59bac89735ba61a77d9269c3586_520x464.png"></p><p>练习题: 有 abcde 五个元素依次入栈 (过程中可以出栈),以下得到的出栈结果是错误的是?</p><p>a. edcba</p><p>b. badec</p><p>c. eacbd</p><p>d. bcdae</p><p>答案: C 选项是错误的! 根据栈的特点不可能得到 C 这个出栈结果.</p><p>练习题: 有 abc 三个元素依次入栈（过程中可以出栈），以下得到的出栈结果是错误的是？<br>a. bac<br>b. cba<br>c. abc<br>d. cab</p><h3 id="实现方式"><a href="#实现方式" class="headerlink" title="实现方式"></a>实现方式</h3><p>栈的实现有两种方式:</p><ul><li>顺序栈 (数组实现)</li><li>链式栈 (链表实现)</li></ul><h4 id="顺序栈"><a href="#顺序栈" class="headerlink" title="顺序栈"></a>顺序栈</h4><p>用 <code>数组</code> 来实现一个栈结构.</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Stack</span> </span>&#123;</span><br><span class="line">    <span class="keyword">constructor</span>() &#123;</span><br><span class="line">        <span class="keyword">this</span>._stack = [] <span class="comment">// 桶中的数据</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 入栈操作</span></span><br><span class="line">    push(data) &#123;</span><br><span class="line">        <span class="keyword">this</span>._stack.push(data)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 出栈操作</span></span><br><span class="line">    pop() &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">this</span>._stack.pop()</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 清空栈</span></span><br><span class="line">    clear() &#123;</span><br><span class="line">        <span class="keyword">this</span>._stack = []</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 获取栈中元素的数量</span></span><br><span class="line">    count() &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">this</span>._stack.length</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 创建一个栈</span></span><br><span class="line"><span class="keyword">const</span> s = <span class="keyword">new</span> Stack()</span><br><span class="line"><span class="comment">// 入栈几个数据</span></span><br><span class="line">s.push(<span class="string">'h'</span>)</span><br><span class="line">s.push(<span class="string">'e'</span>)</span><br><span class="line">s.push(<span class="string">'l'</span>)</span><br><span class="line">s.push(<span class="string">'l'</span>)</span><br><span class="line">s.push(<span class="string">'o'</span>)</span><br><span class="line"><span class="built_in">console</span>.log(s); <span class="comment">// Stack &#123; _stack: [ 'h', 'e', 'l', 'l', 'o' ] &#125;</span></span><br></pre></td></tr></table></figure><p>面试题: 使用 JS 来模拟一个栈。</p><h4 id="链式栈"><a href="#链式栈" class="headerlink" title="链式栈"></a>链式栈</h4><p>用 <code>链表</code> 来实现栈的结构。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 链式栈</span></span><br><span class="line"><span class="comment">// 定义节点类</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Node</span> </span>&#123;</span><br><span class="line">    <span class="keyword">constructor</span>(data) &#123;</span><br><span class="line">        <span class="keyword">this</span>.data = data <span class="comment">// 节点中的数据</span></span><br><span class="line">        <span class="keyword">this</span>.next = <span class="literal">null</span> <span class="comment">// 下一个节点</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 栈</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">LinkedListStack</span> </span>&#123;</span><br><span class="line">    <span class="keyword">constructor</span>() &#123;</span><br><span class="line">        <span class="keyword">this</span>.head = <span class="literal">null</span>  <span class="comment">// 栈顶元素</span></span><br><span class="line">        <span class="keyword">this</span>.length = <span class="number">0</span> <span class="comment">// 栈中元素的个数</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 入栈</span></span><br><span class="line">    push(data) &#123;</span><br><span class="line">        <span class="comment">// 1. 创建一个新的节点</span></span><br><span class="line">        <span class="keyword">let</span> newNode = <span class="keyword">new</span> Node(data)</span><br><span class="line">        <span class="comment">// 2. 让这个新节点指向原来的栈顶节点</span></span><br><span class="line">        <span class="keyword">if</span> (<span class="keyword">this</span>.head === <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="comment">// 如果是空节点，那么 head 直接指向这个新节点</span></span><br><span class="line">            <span class="keyword">this</span>.head = newNode</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">// 让新节点指向原栈顶节点</span></span><br><span class="line">            newNode.next = <span class="keyword">this</span>.head</span><br><span class="line">            <span class="comment">// 让新节点变成栈顶</span></span><br><span class="line">            <span class="keyword">this</span>.head = newNode</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 3. 栈中元素数量+1</span></span><br><span class="line">        <span class="keyword">this</span>.length++</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 出栈</span></span><br><span class="line">    pop() &#123;</span><br><span class="line">        <span class="comment">// 1. 先取出栈顶节点中的数据</span></span><br><span class="line">        <span class="keyword">let</span> data = <span class="keyword">this</span>.head.data</span><br><span class="line">        <span class="comment">// 2. 把 head 指针指向下一个元素（删除原栈顶元素）</span></span><br><span class="line">        <span class="keyword">this</span>.head = <span class="keyword">this</span>.head.next</span><br><span class="line">        <span class="comment">// 3. 栈中元素的数量-1</span></span><br><span class="line">        <span class="keyword">this</span>.length--</span><br><span class="line">        <span class="comment">// 4. 返回原栈顶元素</span></span><br><span class="line">        <span class="keyword">return</span> data</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 创建一个栈</span></span><br><span class="line"><span class="keyword">const</span> ls = <span class="keyword">new</span> LinkedListStack()</span><br><span class="line"><span class="comment">// 入栈几个数据</span></span><br><span class="line">ls.push(<span class="string">'a'</span>)</span><br><span class="line">ls.push(<span class="string">'b'</span>)</span><br><span class="line">ls.push(<span class="string">'c'</span>)</span><br><span class="line">ls.push(<span class="string">'d'</span>)</span><br><span class="line">ls.push(<span class="string">'e'</span>)</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(ls.pop());</span><br><span class="line"><span class="built_in">console</span>.log(ls.pop());</span><br><span class="line"><span class="built_in">console</span>.log(ls.pop());</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(ls);</span><br><span class="line"><span class="built_in">console</span>.log(ls.length);</span><br></pre></td></tr></table></figure><p>运行结果：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">e</span><br><span class="line">d</span><br><span class="line">c</span><br><span class="line">LinkedListStack &#123;</span><br><span class="line">  head: Node &#123; <span class="attr">data</span>: <span class="string">'b'</span>, <span class="attr">next</span>: Node &#123; <span class="attr">data</span>: <span class="string">'a'</span>, <span class="attr">next</span>: <span class="literal">null</span> &#125; &#125;,</span><br><span class="line">  length: <span class="number">2</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="number">2</span></span><br></pre></td></tr></table></figure><br><h2 id="队列"><a href="#队列" class="headerlink" title="队列"></a>队列</h2><h3 id="介绍-2"><a href="#介绍-2" class="headerlink" title="介绍"></a>介绍</h3><h4 id="特点-2"><a href="#特点-2" class="headerlink" title="特点"></a>特点</h4><p>队列（queue）是一种 <code>先进先出</code>（FIFO:First In Fist Out) 的线性数据结构。<br>现实生活中，我们经常需要排队，比如我们去食堂打饭，就要先排队，先来的先买，后到的后买，<code>不允许插队</code>。</p><p>队头出、队尾进。</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1getdvtnxqvj30nq068gmx.jpg" alt="3974e87362870f94b5e4c25924df493c_854x224.png"></p><h4 id="实现方式-1"><a href="#实现方式-1" class="headerlink" title="实现方式"></a>实现方式</h4><p>栈的实现有两种方式：</p><ul><li>顺序栈（数组实现）</li><li>链式栈（链表实现）</li></ul><h4 id="应用场景"><a href="#应用场景" class="headerlink" title="应用场景"></a>应用场景</h4><ul><li>秒杀下单时：先下单的人排在前面</li><li>抢火车票</li></ul><p>……</p><br><h2 id="散列表"><a href="#散列表" class="headerlink" title="散列表"></a>散列表</h2><h3 id="介绍-3"><a href="#介绍-3" class="headerlink" title="介绍"></a>介绍</h3><p>散列表（Hash table，也叫哈希表），是通过 <code>键</code> 对数据进行映射存储的一种线性结构。</p><p>简单的说，就是 <code>键-值</code> 对的数据结构。</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gete4345atj30l60lyh2q.jpg" alt="6d527b9737a96fbee17ba562e779a6a6_762x790.png"></p><h4 id="JS-中的-对象-和-Map"><a href="#JS-中的-对象-和-Map" class="headerlink" title="JS 中的 对象 和 Map"></a>JS 中的 对象 和 Map</h4><p>JS 中其实已经有了散列表的实现：一般二叉树</p><ul><li>对象（Object）：键只能是字符串</li><li>ES6 中的 映射(Map) : 键可以是各种类型</li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 对象</span></span><br><span class="line"><span class="keyword">const</span> people = &#123;</span><br><span class="line">    name: <span class="string">'tom'</span>,</span><br><span class="line">    age: <span class="number">10</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">console</span>.log(people.name)</span><br><span class="line"><span class="built_in">console</span>.log(people.age)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 映射</span></span><br><span class="line"><span class="keyword">const</span> people = <span class="keyword">new</span> <span class="built_in">Map</span>()</span><br><span class="line">people.set(<span class="string">'name'</span>, <span class="string">'tom'</span>)</span><br><span class="line">people.set(<span class="string">'age'</span>, <span class="number">10</span>)</span><br><span class="line"><span class="built_in">console</span>.log(people.get(<span class="string">'name'</span>))</span><br><span class="line"><span class="built_in">console</span>.log(people.get(<span class="string">'age'</span>))</span><br></pre></td></tr></table></figure><h4 id="散列函数"><a href="#散列函数" class="headerlink" title="散列函数"></a>散列函数</h4><p>散列表中的值也是保存在数组中的，但数组只能通过下标访问，如何能够通过键来访问呢？</p><p>通过散列函数进行映射：</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1getecgvqfjj30w40fwqiu.jpg" alt="78fe2cddd085497aacff411a66c8dda0_1156x572.png"></p><p>我们需要设计一个函数处理键，然后把键映射到数组中的某一个下标上。</p><p>好的散列函数有以下特点：</p><ul><li>不能太复杂</li><li>计算出来的值要尽可能的随机并且均匀的分布</li></ul><p>选择散列函数时还跟数据类型有关：</p><ul><li>整数： 直接对数组长度求模即可</li><li>字符串：每个字母都对应一个 ASCII 码，所以可以对字符串中的每个字母求 ASCII 码并求和，转成数字。</li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 将一个键转成数组中的一个下标</span></span><br><span class="line"><span class="comment">// 参数一、键</span></span><br><span class="line"><span class="comment">// 参数二、数组的长度</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">hash</span>(<span class="params">key, arrLength</span>) </span>&#123;</span><br><span class="line">    <span class="comment">// 1. 将 key 转成数字</span></span><br><span class="line">    <span class="comment">//      1.1 在计算机中的A-Z，0-9已经一些常用的符号都对应一个 ASCII （阿斯克）码 (数字)</span></span><br><span class="line">    <span class="comment">//      1.2 将字符串转成数字： 将字符串中的每一个字符都转成 ASCII 码，然后把所有 ASCII 码加到一起</span></span><br><span class="line">    <span class="keyword">let</span> num = <span class="number">0</span></span><br><span class="line">    <span class="comment">// 把每个字母的 ASCII 加到一起</span></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; key.length; i++) &#123;</span><br><span class="line">        num += key.charCodeAt(i)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 2. 对数组长度取模</span></span><br><span class="line">    <span class="keyword">return</span> num &amp; arrLength</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>有没有可能不同的键在经过 hash 函数计算之后得到两个相同的值呢？<br>答：绝对有。</p><p>所以为了尽量减少计算出相同值的情况，我们可以优化一下 hash 函数：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 将一个键转成数组中的一个下标</span></span><br><span class="line"><span class="comment">// 参数一、键</span></span><br><span class="line"><span class="comment">// 参数二、数组的长度</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">hash</span>(<span class="params">key, arrLength</span>) </span>&#123;</span><br><span class="line">    <span class="comment">// 1. 将 key 转成数字</span></span><br><span class="line">    <span class="comment">//      1.1 在计算机中的A-Z，0-9已经一些常用的符号都对应一个 ASCII （阿斯克）码 (数字)</span></span><br><span class="line">    <span class="comment">//      1.2 将字符串转成数字： 将字符串中的每一个字符都转成 ASCII 码，然后把所有 ASCII 码加到一起</span></span><br><span class="line">    <span class="keyword">let</span> num = <span class="number">0</span></span><br><span class="line">    <span class="comment">// 定义一个质数 (质数：)</span></span><br><span class="line">    <span class="keyword">const</span> H = <span class="number">131</span></span><br><span class="line">    <span class="comment">// 把每个字母的 ASCII 加到一起</span></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; key.length; i++) &#123;</span><br><span class="line">        num += H * num + key.charCodeAt(i)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 2. 对数组长度取模</span></span><br><span class="line">    <span class="keyword">return</span> num &amp; arrLength</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="散列冲突"><a href="#散列冲突" class="headerlink" title="散列冲突"></a>散列冲突</h4><p>散列冲突是无法避免的，所以当遇到冲突时我们一般有两种解决办法：</p><ul><li>开放寻址法</li><li>链表法</li></ul><h5 id="开放寻址法"><a href="#开放寻址法" class="headerlink" title="开放寻址法"></a>开放寻址法</h5><p>适用场景：数组容器远大于实际要保存的数据的量。<br>当发现在数组中相应下标的位置已经被其他元素占用了，那么就找这个元素后面的元素，如果为空就放进去，如果也被占用了，就再向后一个元素查找直到遇到一个空的位置为止。<br>比如：</p><ol><li>计算的 hash 值是 2但发现数组中 下标为 2 的位置被其他元素占用了<img src="http://ww1.sinaimg.cn/large/007WurYGgy1getg336qvaj31760cm493.jpg" alt="c8601289dbc83926c70c4105a5b3d84a_1554x454.png"></li><li>向后挪一位，发现也被占用了：<img src="http://ww1.sinaimg.cn/large/007WurYGgy1getg3ezl1rj317a0c8qdk.jpg" alt="f4f3bd3e3b34ec7e60e1d011ef67a5ce_1558x440.png"></li><li>再向后挪一位：发现这个位置是空的，就放进去<img src="http://ww1.sinaimg.cn/large/007WurYGgy1getg44qn1wj318k0bwqds.jpg" alt="b34722d0f3d081ff2031a7439533ffd3_1604x428.png"></li></ol><h5 id="链表法"><a href="#链表法" class="headerlink" title="链表法"></a>链表法</h5><p>数组中每个位置上放一个链表，相关键的元素都挂到链表上：</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1getg55iebpj317y0doakh.jpg" alt="205fbba677eabeb2af827c9fd061dd3a_1582x492.png"></p><h3 id="Javascript-代码实现"><a href="#Javascript-代码实现" class="headerlink" title="Javascript 代码实现"></a>Javascript 代码实现</h3><p>开发寻址法的散列表：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="comment">// 定义一个散列表，实现键值对操作（最终：让数组可以通过 KEY-VALUE 对的方式来操作）</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Node</span> </span>&#123;</span><br><span class="line">    <span class="keyword">constructor</span>(key, value) &#123;</span><br><span class="line">        <span class="keyword">this</span>.key = key</span><br><span class="line">        <span class="keyword">this</span>.value = value</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">HashTable</span> </span>&#123;</span><br><span class="line">    <span class="keyword">constructor</span>(length) &#123;</span><br><span class="line">        <span class="comment">// 保存数据的数组长度</span></span><br><span class="line">        <span class="keyword">this</span>.length = length || <span class="number">137</span>     <span class="comment">// 默认 137</span></span><br><span class="line">        <span class="keyword">this</span>.data = <span class="keyword">new</span> <span class="built_in">Array</span>(<span class="keyword">this</span>.length)  <span class="comment">// 保存数据的数组</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    hash(key) &#123;</span><br><span class="line">        <span class="comment">// 1. 将 key 转成数字</span></span><br><span class="line">        <span class="comment">//      1.1 在计算机中的A-Z，0-9已经一些常用的符号都对应一个 ASCII （阿斯克）码 (数字)</span></span><br><span class="line">        <span class="comment">//      1.2 将字符串转成数字： 将字符串中的每一个字符都转成 ASCII 码，然后把所有 ASCII 码加到一起</span></span><br><span class="line">        <span class="keyword">let</span> num = <span class="number">0</span></span><br><span class="line">        <span class="comment">// 定义一个质数 (质数：)</span></span><br><span class="line">        <span class="keyword">const</span> H = <span class="number">131</span></span><br><span class="line">        <span class="comment">// 把每个字母的 ASCII 加到一起</span></span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; key.length; i++) &#123;</span><br><span class="line">            num += H * num + key.charCodeAt(i)</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 2. 对数组长度取模</span></span><br><span class="line">        <span class="keyword">return</span> num &amp; <span class="keyword">this</span>.length</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 存取数据</span></span><br><span class="line">    <span class="keyword">set</span>(name, value) &#123;</span><br><span class="line">        <span class="comment">// 先转成下标</span></span><br><span class="line">        <span class="keyword">let</span> i = <span class="keyword">this</span>.hash(name)</span><br><span class="line">        <span class="comment">// 找为空的格子</span></span><br><span class="line">        <span class="keyword">let</span> index = <span class="number">0</span> <span class="comment">// 移动的次数</span></span><br><span class="line">        <span class="keyword">while</span> (<span class="keyword">this</span>.data[i] !== <span class="literal">undefined</span>) &#123;</span><br><span class="line">            <span class="comment">// 移动的次数等于数组的长度，说明数组中没有空格</span></span><br><span class="line">            <span class="keyword">if</span> (++index &gt;= <span class="keyword">this</span>.data.length) &#123;</span><br><span class="line">                <span class="comment">// 直接退出函数</span></span><br><span class="line">                <span class="keyword">return</span> <span class="literal">false</span></span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">// 向后一位</span></span><br><span class="line">            i++</span><br><span class="line">            <span class="comment">// 如果下标超出数组，设置为0</span></span><br><span class="line">            <span class="keyword">if</span> (i &gt;= <span class="keyword">this</span>.data.length) &#123;</span><br><span class="line">                i = <span class="number">0</span></span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 把数据放到空格上</span></span><br><span class="line">        <span class="comment">// 新建一个包含键和值的节点</span></span><br><span class="line">        <span class="keyword">let</span> node = <span class="keyword">new</span> Node(name, value)</span><br><span class="line">        <span class="keyword">this</span>.data[i] = node</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 获取数据</span></span><br><span class="line">    <span class="keyword">get</span>(name) &#123;</span><br><span class="line">        <span class="comment">// 先转成下标</span></span><br><span class="line">        <span class="keyword">let</span> i = <span class="keyword">this</span>.hash(name)</span><br><span class="line">        <span class="comment">// 如果当前这个格子中的键不等于要读取的键</span></span><br><span class="line">        <span class="keyword">let</span> index = <span class="number">0</span> <span class="comment">// 移动的次数</span></span><br><span class="line">        <span class="keyword">while</span> (<span class="keyword">this</span>.data[i].key != name) &#123;</span><br><span class="line">            <span class="comment">// 移动的次数等于数组的长度，说明数组中没有空格</span></span><br><span class="line">            <span class="keyword">if</span> (++index &gt;= <span class="keyword">this</span>.data.length) &#123;</span><br><span class="line">                <span class="comment">// 直接退出函数</span></span><br><span class="line">                <span class="keyword">return</span> <span class="literal">null</span></span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">// 下标向后挪一位</span></span><br><span class="line">            i++</span><br><span class="line">            <span class="comment">// 如果下标超出数组，设置为0</span></span><br><span class="line">            <span class="keyword">if</span> (i &gt;= <span class="keyword">this</span>.data.length) &#123;</span><br><span class="line">                i = <span class="number">0</span></span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 找到对应的键，把值返回</span></span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">this</span>.data[i].value</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> ht = <span class="keyword">new</span> HashTable()</span><br><span class="line">ht.set(<span class="string">'name'</span>, <span class="string">'tom'</span>)</span><br><span class="line">ht.set(<span class="string">'age'</span>, <span class="number">10</span>)</span><br><span class="line"><span class="built_in">console</span>.log(ht.get(<span class="string">'name'</span>)); <span class="comment">// tom</span></span><br><span class="line"><span class="built_in">console</span>.log(ht.get(<span class="string">'age'</span>)); <span class="comment">// 10</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 多个不同的键，在 hash 计算之后得到了同一个下标</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// console.log(ht.hash('ftr4'));</span></span><br><span class="line"><span class="comment">// console.log(ht.hash('de2'));</span></span><br><span class="line"><span class="comment">// console.log(ht.hash('fe'));</span></span><br><span class="line"><span class="comment">// console.log(ht.hash('sc3'));</span></span><br><span class="line"><span class="comment">// console.log(ht.hash('4fa'));</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 以下这两个键计算 hash 之后是相同的（冲突）</span></span><br><span class="line">ht.set(<span class="string">'fgr4'</span>, <span class="number">200</span>)</span><br><span class="line">ht.set(<span class="string">'ds2'</span>, <span class="number">500</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 输出之后值都正常，说明解决了冲突问题</span></span><br><span class="line"><span class="built_in">console</span>.log(ht.get(<span class="string">'fgr4'</span>));</span><br><span class="line"><span class="built_in">console</span>.log(ht.get(<span class="string">'ds2'</span>));</span><br></pre></td></tr></table></figure><br><h1 id="树"><a href="#树" class="headerlink" title="树"></a>树</h1><h2 id="树的概念"><a href="#树的概念" class="headerlink" title="树的概念"></a>树的概念</h2><p>树结构是一种 <code>一对多</code> 的数据结构。</p><h3 id="特点："><a href="#特点：" class="headerlink" title="特点："></a>特点：</h3><ul><li><code>有且只有</code> 一个根节点</li><li>每个节点 <code>最多</code> 只能有 <code>一个父节点</code></li><li>每个节点<code>可以</code> 有 <code>多个子节点</code></li></ul><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1getjcmuy13j316e0qaqg4.jpg" alt="dc7f67d9617c9dfe791f86cdfdc4304e_1526x946.png"></p><h4 id="高度、深度和层"><a href="#高度、深度和层" class="headerlink" title="高度、深度和层"></a>高度、深度和层</h4><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1getjeo76vlj31660n6k3h.jpg" alt="e91e095e8c68e6fbef02e201b9bce9c3_1518x834.png"></p><h4 id="度"><a href="#度" class="headerlink" title="度"></a>度</h4><p>节点的度：节点的子节点的数量。<br>树的度：树中度最大的节点的度。</p><h4 id="节点关系"><a href="#节点关系" class="headerlink" title="节点关系"></a>节点关系</h4><p>节点分为：</p><ul><li>根节点</li><li>子节点</li><li>父节点</li><li>叶子节点</li><li>兄弟节点</li></ul><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1getjf4nlepj31720t04p9.jpg" alt="c21d1b26cea8b96b14c72a8ebbabff2b_1550x1044.png"></p><br><h2 id="一般二叉树"><a href="#一般二叉树" class="headerlink" title="一般二叉树"></a>一般二叉树</h2><h3 id="介绍-4"><a href="#介绍-4" class="headerlink" title="介绍"></a>介绍</h3><h4 id="特点-3"><a href="#特点-3" class="headerlink" title="特点"></a>特点</h4><p>二叉树： <code>最多只有两个</code> 子节点的树。度为2的数。</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1getjidjm13j313e0oytix.jpg" alt="b474cd10635fa66b483b88c0b9c629bd_1418x898.png"></p><h4 id="分类"><a href="#分类" class="headerlink" title="分类"></a>分类</h4><p>二叉树分为：</p><ul><li>满二叉树</li><li>完全二叉树</li><li>平衡二叉树</li><li>二叉搜索树</li></ul><h5 id="满二叉树"><a href="#满二叉树" class="headerlink" title="满二叉树"></a>满二叉树</h5><p>除了最后一层叶子结构之外，其他节点都有两个子节点的树。</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1getjioahfuj30a606gjs5.jpg" alt="6ca9ec1917db04b1b78e2607ad259caa_366x232.png"></p><h5 id="完全二叉树"><a href="#完全二叉树" class="headerlink" title="完全二叉树"></a>完全二叉树</h5><p>除了最后缺的几个节点不考虑之外，剩下的节点和一个满二叉结构节点数完全相同。</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1getjixpfprj30ly0a477u.jpg" alt="4cf03c460fda250401998c1a9a67daf4_790x364.png"></p><h5 id="平衡二叉树"><a href="#平衡二叉树" class="headerlink" title="平衡二叉树"></a>平衡二叉树</h5><p>任一节点左右子节点的 <code>高度差</code> 小于等于 |1|。<br>节点高度：从这个节点到叶子节点最多的边数。</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1getjj9far6j30m40e27ed.jpg" alt="93229219901e21e810caef18799c72d9_796x506.png"></p><h5 id="二叉搜索树（BST-Binary-Search-Tree）"><a href="#二叉搜索树（BST-Binary-Search-Tree）" class="headerlink" title="二叉搜索树（BST-Binary Search Tree）"></a>二叉搜索树（BST-Binary Search Tree）</h5><p>规则：</p><ol><li>任意一个节点的左子节点都小于这个节点</li><li>任意一个节点的右子节点都大于这个节点</li></ol><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1getjjz3jc2j30l20fcgr1.jpg" alt="3a2f485a68582d4cb5786ef6a874c08a_758x552.png"></p><h4 id="存储方式"><a href="#存储方式" class="headerlink" title="存储方式"></a>存储方式</h4><p>二叉树的存储方式：</p><ul><li>顺序存储（用数组）</li><li>链式存储（用链表）</li></ul><h5 id="链式存储"><a href="#链式存储" class="headerlink" title="链式存储"></a>链式存储</h5><p>每个节点都有 左、右 两个指针，指向左右两个子节点。</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1getjl0r7f4j30q00jo12r.jpg" alt="25092e010b3eedc751418fa9f04b4c4f_936x708.png"></p><p>节点类：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Node</span> </span>&#123;</span><br><span class="line">    construct(data) &#123;</span><br><span class="line">        <span class="keyword">this</span>.data = data <span class="comment">// 数据</span></span><br><span class="line">        <span class="keyword">this</span>.left = <span class="literal">null</span>  <span class="comment">// 左子节点</span></span><br><span class="line">        <span class="keyword">this</span>.right = <span class="literal">null</span>  <span class="comment">// 右子节点</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h5 id="顺序存储"><a href="#顺序存储" class="headerlink" title="顺序存储"></a>顺序存储</h5><p>使用数组存储二叉树。<br>存储完之后必须要满公式：<br>情况一、（如果根节点保存在 0 这个下标时的公式）<br>第i个节点的左子节点下标：2i+1<br>第i个节点的右子节点下标：2i+2<br>第i个节点的父节点下标；Math.floor(i/2)</p><p>情况二、根节点保存在1这个位置时：</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1getjlrbpy8j30ou0g2dph.jpg" alt="720cdc446cc85cec73da370a66751d22_894x578.png"></p><p>顺序存储比较适合 <code>完全二叉树</code>，否则会比较浪费空间（有很多空位）：</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1getjmaiheaj30jy0fgtfw.jpg" alt="a92e9c605aa3ac9266429681aa605e75_718x556.png"></p><br><h2 id="树和森林和二叉树的转换"><a href="#树和森林和二叉树的转换" class="headerlink" title="树和森林和二叉树的转换"></a>树和森林和二叉树的转换</h2><blockquote><p>引用：<a href="https://www.cnblogs.com/wangwenji/p/10223888.html" target="_blank" rel="noopener">https://www.cnblogs.com/wangwenji/p/10223888.html</a></p></blockquote><h3 id="森林"><a href="#森林" class="headerlink" title="森林"></a>森林</h3><p>多个树在一起就是森林。</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gexxecabd6j30g8082di9.jpg" alt="image.png"></p><h3 id="森林、树、二叉树之间的转换"><a href="#森林、树、二叉树之间的转换" class="headerlink" title="森林、树、二叉树之间的转换"></a>森林、树、二叉树之间的转换</h3><h4 id="树转二叉树"><a href="#树转二叉树" class="headerlink" title="树转二叉树"></a>树转二叉树</h4><p>流程：<br>（1）加线。在所有兄弟结点之间加一条连线。<br>（2）去线。树中的每个结点，只保留它与第一个孩子结点的连线，删除它与其它孩子结点之间的连线。<br>（3）层次调整。以树的根节点为轴心，将整棵树顺时针旋转一定角度，使之结构层次分明。</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gexxf1p9w2j30qg0me7g1.jpg" alt="image.png"></p><h4 id="森林转二叉树"><a href="#森林转二叉树" class="headerlink" title="森林转二叉树"></a>森林转二叉树</h4><p>流程：<br>（1）把每棵树转换为二叉树。<br>（2）第一棵二叉树不动，从第二棵二叉树开始，依次把后一棵二叉树的根结点作为前一棵二叉树的根结点的右孩子，用线连接起来。</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gexxfoj2fgj30v40k8qdx.jpg" alt="image.png"></p><h4 id="二叉树转成树"><a href="#二叉树转成树" class="headerlink" title="二叉树转成树"></a>二叉树转成树</h4><p>流程：<br>（1）加线。若某结点X的左孩子结点存在，则将这个左孩子的右孩子结点、右孩子的右孩子结点、右孩子的右孩子的右孩子结点…，都作为结点X的孩子。将结点X与这些右孩子结点用线连接起来。<br>（2）去线。删除原二叉树中所有结点与其右孩子结点的连线。<br>（3）层次调整。</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gexxgclvsij30rs0nqwqy.jpg" alt="image.png"></p><h4 id="二叉树转成森林"><a href="#二叉树转成森林" class="headerlink" title="二叉树转成森林"></a>二叉树转成森林</h4><p>假如一棵二叉树的根节点有右孩子，则这棵二叉树能够转换为森林，否则将转换为一棵树。</p><p>（1）从根节点开始，若右孩子存在，则把与右孩子结点的连线删除。再查看分离后的二叉树，若其根节点的右孩子存在，则连线删除…。直到所有这些根节点与右孩子的连线都删除为止。<br>（2）将每棵分离后的二叉树转换为树。</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gexxgvrxjqj30ui0nods6.jpg" alt="image.png"></p><br><h2 id="二叉树的遍历"><a href="#二叉树的遍历" class="headerlink" title="二叉树的遍历"></a>二叉树的遍历</h2><h3 id="介绍-5"><a href="#介绍-5" class="headerlink" title="介绍"></a>介绍</h3><p>遍历：依次访问树中的每个节点一次。</p><p>前序（根）遍历：根左右。<br>中序（根）遍历：左根中。<br>后序（根）遍历：左右根。</p><h3 id="遍历方法"><a href="#遍历方法" class="headerlink" title="遍历方法"></a>遍历方法</h3><p>二叉树的遍历分为四种：</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1getjnz33njj317i08418k.jpg" alt="43fb8bece32c0ccaaec1e6be7b97247f_1566x292.png"></p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1getjoijytnj319w0eqx3a.jpg" alt="90b7bbd0471620d0f5c2942e63a5dc26_1652x530.png"></p><p>练习：对下面这棵树的三种遍历方式是？</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1getjoyy0msj30c608mwgc.jpg" alt="9b43b4a19f386c4cab572e7404787941_438x310.png"></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">答案：</span><br><span class="line">前序遍历（根左右）：50，45，20，10，15，25，40，35，30</span><br><span class="line">中序遍历（左根右）：10，20，15，45，25，50，35，40，30</span><br><span class="line">后序遍历（左右根）：10，15，20，25，45，35，30，40，50</span><br></pre></td></tr></table></figure><h3 id="遍历代码实现"><a href="#遍历代码实现" class="headerlink" title="遍历代码实现"></a>遍历代码实现</h3><h4 id="前、中、后序遍历"><a href="#前、中、后序遍历" class="headerlink" title="前、中、后序遍历"></a>前、中、后序遍历</h4><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gewmdxea8uj308h0rmdgm.jpg" alt="Snipaste_2020-05-18_15-08-47.png"></p><p>层序遍历</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1getjoyy0msj30c608mwgc.jpg" alt="9b43b4a19f386c4cab572e7404787941_438x310.png"></p><h3 id="层序遍历代码实现"><a href="#层序遍历代码实现" class="headerlink" title="层序遍历代码实现"></a>层序遍历代码实现</h3><p>需要借助 <code>队列</code> 来实现层序遍历：</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gewmg85rijj30dt0a6t8x.jpg" alt="Snipaste_2020-05-18_15-12-00.png"></p><br><h2 id="搜索二叉树"><a href="#搜索二叉树" class="headerlink" title="搜索二叉树"></a>搜索二叉树</h2><p>搜索二叉树（BST）。</p><p>规则：</p><ol><li>任意一个节点的左子节点都小于这个节点</li><li>任意一个节点的右子节点都大于这个节点</li></ol><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1getjqmbwggj30tc0lun79.jpg" alt="9b43b4a19f386c4cab572e7404787941_438x310.png"></p><h3 id="应用场景-1"><a href="#应用场景-1" class="headerlink" title="应用场景"></a>应用场景</h3><p>这种树的搜索速度：O(logn)，速度非常快。<br>比如：从10亿条记录中查找任意一条记录，最多需要比较30多次。</p><h3 id="JavaScript-代码实现"><a href="#JavaScript-代码实现" class="headerlink" title="JavaScript 代码实现"></a>JavaScript 代码实现</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 定义节点类</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Node</span> </span>&#123;</span><br><span class="line">    <span class="keyword">constructor</span>(data) &#123;</span><br><span class="line">        <span class="keyword">this</span>.data =  data <span class="comment">// 数据</span></span><br><span class="line">        <span class="keyword">this</span>.left = <span class="literal">null</span>   <span class="comment">// 左子节点</span></span><br><span class="line">        <span class="keyword">this</span>.right = <span class="literal">null</span>   <span class="comment">// 右子节点</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// BST树</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">BinarySearchTree</span> </span>&#123;</span><br><span class="line">    <span class="keyword">constructor</span>() &#123;</span><br><span class="line">        <span class="keyword">this</span>.root = <span class="literal">null</span>    <span class="comment">// 根节点</span></span><br><span class="line">        <span class="keyword">this</span>.length = <span class="number">0</span>   <span class="comment">// 树中节点的数量</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 向树中插入一条记录</span></span><br><span class="line">    insert(data) &#123;</span><br><span class="line">        <span class="comment">// 1. 创建新的节点</span></span><br><span class="line">        <span class="keyword">let</span> newNode = <span class="keyword">new</span> Node(data)</span><br><span class="line">        <span class="comment">// 2.放到树中</span></span><br><span class="line">        <span class="comment">// 如果是空树</span></span><br><span class="line">        <span class="keyword">if</span>(<span class="keyword">this</span>.root === <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="comment">// 设置这个新节点为树根</span></span><br><span class="line">            <span class="keyword">this</span>.root = newNode</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">// 从根节点开始比较</span></span><br><span class="line">            <span class="keyword">this</span>._insert(<span class="keyword">this</span>.root, newNode)</span><br><span class="line">        &#125; </span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    _insert(node, newNode) &#123;</span><br><span class="line">        <span class="comment">// 小于向左走</span></span><br><span class="line">        <span class="keyword">if</span>(newNode.data &lt; node.data) &#123;</span><br><span class="line">            <span class="comment">// 判断是否有左子节点</span></span><br><span class="line">            <span class="keyword">if</span>(node.left === <span class="literal">null</span>) &#123;</span><br><span class="line">                <span class="comment">// 设置这个新节点为左子节点</span></span><br><span class="line">                node.left = newNode</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="comment">// 递归，继承用新节点和左子节点比较</span></span><br><span class="line">                <span class="keyword">this</span>._insert(node.left, newNode)</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">// 判断是否有右子节点</span></span><br><span class="line">            <span class="keyword">if</span>(node.right === <span class="literal">null</span>) &#123;</span><br><span class="line">                <span class="comment">// 设置这个新节点为右子节点</span></span><br><span class="line">                node.right = newNode</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="comment">// 递归，继承用新节点和右子节点比较</span></span><br><span class="line">                <span class="keyword">this</span>._insert(node.right, newNode)</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 判断树中是否包含某一个数</span></span><br><span class="line">    has(data) &#123;</span><br><span class="line">        <span class="comment">// 从根节点开始查找</span></span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">this</span>._has(<span class="keyword">this</span>.root, data)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    _has(node, data) &#123;</span><br><span class="line">        <span class="comment">// 如果节点为空，说明树中没有这个数</span></span><br><span class="line">        <span class="keyword">if</span>(node == <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span></span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 如果值和前节点值相同，找到了</span></span><br><span class="line">        <span class="keyword">if</span>(data == node.data) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">true</span></span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span>(data &lt; node.data) &#123;</span><br><span class="line">            <span class="comment">// 到左子树中查找</span></span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">this</span>._has(node.left, data)</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span>(data &gt; node.data) &#123;</span><br><span class="line">             <span class="comment">// 到右子树中查找</span></span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">this</span>._has(node.right, data)</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><h2 id="自平衡二叉树"><a href="#自平衡二叉树" class="headerlink" title="自平衡二叉树"></a>自平衡二叉树</h2><h3 id="介绍-6"><a href="#介绍-6" class="headerlink" title="介绍"></a>介绍</h3><h4 id="概念"><a href="#概念" class="headerlink" title="概念"></a>概念</h4><p>平衡二叉树（Balance Tree，BT）：每个节点的左、右子树的 <code>高度差</code> 最多是1。</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gewmj9588cj30xm0be0wn.jpg" alt="dec5cbf2007f52cbf3aef638b2cf1bbd_1210x410.png"></p><h4 id="平衡因子"><a href="#平衡因子" class="headerlink" title="平衡因子"></a>平衡因子</h4><p>一个节点左子树的高度-右子树的高度</p><h4 id="自平衡二叉树-1"><a href="#自平衡二叉树-1" class="headerlink" title="自平衡二叉树"></a>自平衡二叉树</h4><p>在每次插入、删除节点时，二叉树能够 <code>自动调调整</code>，让自己时刻保持是一棵平衡二叉树。<br>为了让一棵二叉树时刻保持最高的查询速度，必须要让树时刻是一个平衡二叉树。<br>不能让它退化成一个链表，比如：</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gewmkabs92j30g40i0abs.jpg" alt="dc67f2ea8c2dbcc9603eb50df96e2ee7_580x648.png"></p><p>所以我们需要能够自动调整自己，时刻保持平衡的二叉树：自平衡二叉树。</p><p>最常见的两种自平衡二叉树：</p><ol><li>AVL 树</li><li>红黑树：Linux 系统底层的进程抢占管理。</li></ol><h3 id="AVL树"><a href="#AVL树" class="headerlink" title="AVL树"></a>AVL树</h3><h4 id="介绍-7"><a href="#介绍-7" class="headerlink" title="介绍"></a>介绍</h4><ol><li>AVL 树是最早被发明的自平衡二叉树</li><li>AVL 树得名于它的发明者G. M. Adelson-Velsky和E. M. Landis，他们在1962年的论文中发表了它。</li></ol><h4 id="构建-AVL-树"><a href="#构建-AVL-树" class="headerlink" title="构建 AVL 树"></a>构建 AVL 树</h4><p>为了保证一树是时刻保持平衡，我们需要在向节点中插入、删除新节点时通过 <code>旋转</code> 来调整树的结构。<br>如何实现二叉树调整平衡，要通过二叉树的 <code>旋转</code> 来实现。<br>二叉树可以分为四种情况，不同的情况进行不同的旋转：</p><p>L：left 左<br>LL: 左左型<br>R：right 右<br>RR：右右型<br>LR:左右型<br>RL：右左型</p><ul><li>LL型二叉树 ：右旋转</li><li>RR型二叉树：左旋转</li><li>LR型二叉树：先左旋转再右旋转</li><li>RL型二叉树：先右旋转再左旋转</li></ul><h5 id="LL-型"><a href="#LL-型" class="headerlink" title="LL 型"></a>LL 型</h5><p>对于节点倾向于左边的情况，我们称之为 <code>LL型</code>。<br>这个时候我们需要进行 <code>右旋转</code> 操作，使它恢复平衡：</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gewmmxczoqj317g0amjut.jpg" alt="8aa15bcf24fcebe43cd13834a248d5a3_1564x382.png"></p><p>再看一个例子：</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gewmngisfdj318q0cmwjf.jpg" alt="c69429d90549a6b36e2fd04f63371af9_1610x454.png"></p><p>再看一个例子：</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gewmoap911j31860dgn25.jpg" alt="3f52d1633dab9bfd6886677900145958_1590x484.png"></p><h5 id="RR-型"><a href="#RR-型" class="headerlink" title="RR 型"></a>RR 型</h5><p>对于节点倾向于右边的情况，我们称之为 <code>RR型</code>。<br>这个时候我们需要进行 <code>左旋转</code> 操作，使它恢复平衡：</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gewmpok2irj316k0ag77n.jpg" alt="5c3a603ab01eaa71ac8e6fc305171d4d_1532x376.png"></p><p>再看一个例子：</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gewmpyotf4j318a0digqr.jpg" alt="0f0894458395b53ff0febba95191ef60_1594x486.png"></p><p>再看一个例子：</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gewmqmc49wj317y0dsq8f.jpg" alt="ea4ca24c662330b2c046a14825a9ef93_1582x496.png"></p><h5 id="LR-型"><a href="#LR-型" class="headerlink" title="LR 型"></a>LR 型</h5><p>以下树为 LR 型，这种情况需要旋转两次：先左旋转再右旋转：</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gewmrfp9p5j318y090q5y.jpg" alt="8592803091b532a85c27faa120076a24_1618x324.png"></p><p>再看一个例子：</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gewms58df1j319m0akjvx.jpg" alt="aeda8afba4d36e42a639b4576fadd147_1642x380.png"></p><p>再看一个例子：</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gewmsen0rqj318q0ai78p.jpg" alt="1a6ff680606e530bde5d9a13c08d419c_1610x378.png"></p><h5 id="RL-型"><a href="#RL-型" class="headerlink" title="RL 型"></a>RL 型</h5><p>看一个例子：</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gewmtleem9j317u08qad0.jpg" alt="a8106ed98a2061021bd432a96b8adca0_1578x314.png"></p><p>再看一个例子：</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gewmtupa1wj318o0a2dki.jpg" alt="124e72f39c567b3fe7e9adbb8d4bfdad_1608x362.png"></p><p>再看一个例子：</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gewmu4pa0mj318o0a0gqa.jpg" alt="af6ab811a9c454bd9259907c0892928b_1608x360.png"></p><h4 id="代码实现-1"><a href="#代码实现-1" class="headerlink" title="代码实现"></a>代码实现</h4><h5 id="平衡因子-1"><a href="#平衡因子-1" class="headerlink" title="平衡因子"></a>平衡因子</h5><p>总结：</p><ol><li>平衡因子：左子树的高度-右子树的高度</li><li>如果平衡因子大于等于 2 说明这个节点不平衡</li><li>如果平衡因子是正数，说明：L 型（左高）</li><li>如果平衡因子是负数，说明：R 型（右高）</li></ol><h5 id="获取一个的高度"><a href="#获取一个的高度" class="headerlink" title="获取一个的高度"></a>获取一个的高度</h5><p>节点高度：左右节点中到叶子节点最多的边数。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 获取节点高度</span></span><br><span class="line">getHeight(node) &#123;</span><br><span class="line">    <span class="keyword">if</span>(node  ===  <span class="literal">null</span>) <span class="keyword">return</span>  <span class="number">0</span></span><br><span class="line">    <span class="comment">// 左右节点中最长的边数</span></span><br><span class="line">    <span class="keyword">return</span>  <span class="built_in">Math</span>.max(<span class="keyword">this</span>.getHeight(node.left), <span class="keyword">this</span>.getHeight(node.right)) +  <span class="number">1</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h5 id="添加四种旋转方法"><a href="#添加四种旋转方法" class="headerlink" title="添加四种旋转方法"></a>添加四种旋转方法</h5><h6 id="左旋"><a href="#左旋" class="headerlink" title="左旋"></a>左旋</h6><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gewn26h6fkj30lg0ae76l.jpg" alt="8d08c7fc10a70e2752bf6f0420d93166_772x374.png"></p><p>代码：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 左旋转</span></span><br><span class="line">rotateToL(node) &#123;</span><br><span class="line">    <span class="comment">// 1. 取出右子节点（C）</span></span><br><span class="line">    <span class="keyword">let</span> tmp = node.right</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 2. 父节点指向右子节点的左子节点</span></span><br><span class="line">    node.right = tmp.left</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 3. 右子节点的左子节点指向父节点</span></span><br><span class="line">    tmp.left = node</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 4. 返回新的顶点</span></span><br><span class="line">    <span class="keyword">return</span> tmp</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h6 id="右旋"><a href="#右旋" class="headerlink" title="右旋"></a>右旋</h6><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gewn3ktfs0j30ky09qq56.jpg" alt="520d0162daedcc8b84f28fd6eb72eb70_754x350.png"></p><p>代码：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 右旋转</span></span><br><span class="line">rotateToR(node) &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">let</span> tmp = node.left</span><br><span class="line"></span><br><span class="line">    node.left = tmp.right</span><br><span class="line"></span><br><span class="line">    tmp.right = node</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> tmp</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h6 id="先左后右"><a href="#先左后右" class="headerlink" title="先左后右"></a>先左后右</h6><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gewn56fu5mj30m207s762.jpg" alt="06a68bc9f191f71babfd14266967cf8c_794x280.png"></p><p>代码：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">&#x2F;&#x2F; 先左旋再右旋转</span><br><span class="line">rotateToLR(node) &#123;</span><br><span class="line">	&#x2F;&#x2F; 让左子节点左旋转，并让旋转之后的顶点做为左子节点</span><br><span class="line">	node.left &#x3D; this.rotateToL(node.left)</span><br><span class="line">	&#x2F;&#x2F; 再让当前节点右旋转</span><br><span class="line">	return this.rotateToR(node)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h6 id="先右后左"><a href="#先右后左" class="headerlink" title="先右后左"></a>先右后左</h6><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gewn7jh7pcj30mk0760um.jpg" alt="0400dd78b3f3eaaf509843000be7c65c_812x258.png"></p><p>代码：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 先右旋再做旋转</span></span><br><span class="line">rotateToRL(node) &#123;</span><br><span class="line">   <span class="comment">// 让右子节点先右旋转，并用新的顶点作为右子节点</span></span><br><span class="line">   node.right = <span class="keyword">this</span>.rotateToR(node.right)</span><br><span class="line">   <span class="comment">// 当前节点左旋</span></span><br><span class="line">   <span class="keyword">return</span> <span class="keyword">this</span>.rotateToL(node)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h6 id="调整二叉树"><a href="#调整二叉树" class="headerlink" title="调整二叉树"></a>调整二叉树</h6><p>计算一个节点的高度并判断是否平衡，如果不平衡，就判断是什么型并进行相应的旋转以保持平衡：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 调整二叉树为平衡状态</span></span><br><span class="line">keepBalance(node) &#123;</span><br><span class="line">    <span class="comment">// 1. 计算左右子节点的高度</span></span><br><span class="line">    <span class="keyword">let</span> leftHeight = <span class="keyword">this</span>.getHeight(node.left)</span><br><span class="line">    <span class="keyword">let</span> rightHeight = <span class="keyword">this</span>.getHeight(node.right)</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 2. 判断是否不平衡，并判断是 L型 还是 R型</span></span><br><span class="line">    <span class="keyword">if</span> (leftHeight - rightHeight &gt; <span class="number">1</span>) &#123; <span class="comment">// L型</span></span><br><span class="line">        <span class="comment">// 3. 判断左子节点的左右谁高</span></span><br><span class="line">        <span class="keyword">if</span> (<span class="keyword">this</span>.getHeight(node.left.left) &gt; <span class="keyword">this</span>.getHeight(node.left.right)) &#123; <span class="comment">// L型</span></span><br><span class="line">            <span class="comment">// LL 型 -》 右旋转</span></span><br><span class="line">            <span class="keyword">this</span>.rotateToR(node)</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;    <span class="comment">// R型</span></span><br><span class="line">            <span class="comment">// LR： 先左旋转，再右旋转</span></span><br><span class="line">            <span class="keyword">this</span>.rotateToLR(node)</span><br><span class="line">        &#125;</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (rightHeight - leftHeight &gt; <span class="number">1</span>) &#123;   <span class="comment">// R型</span></span><br><span class="line">        <span class="comment">// 4. 判断右子节点的左右谁高</span></span><br><span class="line">        <span class="keyword">if</span> (<span class="keyword">this</span>.getHeight(node.right.left) &gt; <span class="keyword">this</span>.getHeight(node.right.right)) &#123; <span class="comment">// L型</span></span><br><span class="line">            <span class="comment">// RL型 -》 先右旋转再左旋转</span></span><br><span class="line">            <span class="keyword">this</span>.rotateToRL(node)</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">// RR型 -》 左旋转</span></span><br><span class="line">            <span class="keyword">this</span>.rotateToL(node)</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h6 id="在添加节点时检查并调整节点"><a href="#在添加节点时检查并调整节点" class="headerlink" title="在添加节点时检查并调整节点"></a>在添加节点时检查并调整节点</h6><p>在每次添加一个新节点时，都有可能打破平衡，需要检查并调整：<br>修改添加节点的代码，在向儿子节点中添加节点时要重新检查并调整</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gewnfticemj30bl0gc74r.jpg" alt="Snipaste_2020-05-18_15-46-10.png"></p><h4 id="完整-AVL-Tree-代码"><a href="#完整-AVL-Tree-代码" class="headerlink" title="完整 AVL Tree 代码"></a>完整 AVL Tree 代码</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 定义节点类</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Node</span> </span>&#123;</span><br><span class="line">	<span class="keyword">constructor</span>(data) &#123;</span><br><span class="line">		<span class="keyword">this</span>.data = data <span class="comment">// 数据</span></span><br><span class="line">		<span class="keyword">this</span>.left = <span class="literal">null</span>   <span class="comment">// 左子节点</span></span><br><span class="line">		<span class="keyword">this</span>.right = <span class="literal">null</span>   <span class="comment">// 右子节点</span></span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// AVL树(自平衡二叉搜索树)</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AVLTree</span> </span>&#123;</span><br><span class="line">	<span class="keyword">constructor</span>() &#123;</span><br><span class="line">		<span class="keyword">this</span>.root = <span class="literal">null</span>    <span class="comment">// 根节点</span></span><br><span class="line">		<span class="keyword">this</span>.length = <span class="number">0</span>   <span class="comment">// 树中节点的数量</span></span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">// 向树中插入一条记录</span></span><br><span class="line">	insert(data) &#123;</span><br><span class="line">		<span class="comment">// 1. 创建新的节点</span></span><br><span class="line">		<span class="keyword">let</span> newNode = <span class="keyword">new</span> Node(data)</span><br><span class="line"></span><br><span class="line">		<span class="comment">// 2.放到树中</span></span><br><span class="line">		<span class="comment">// 如果是空树</span></span><br><span class="line">		<span class="keyword">if</span> (<span class="keyword">this</span>.root === <span class="literal">null</span>) &#123;</span><br><span class="line">			<span class="comment">// 设置这个新节点为树根</span></span><br><span class="line">			<span class="keyword">this</span>.root = newNode</span><br><span class="line">		&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">			<span class="comment">// 从根节点开始比较</span></span><br><span class="line">			<span class="keyword">this</span>.root = <span class="keyword">this</span>._insert(<span class="keyword">this</span>.root, newNode)</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	_insert(node, newNode) &#123;</span><br><span class="line">		<span class="keyword">if</span> (node === <span class="literal">null</span>) &#123;</span><br><span class="line">			node = newNode</span><br><span class="line">			<span class="keyword">return</span> node</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="comment">// 小于向左走</span></span><br><span class="line">		<span class="keyword">if</span> (newNode.data &lt; node.data) &#123;</span><br><span class="line">			<span class="comment">// 判断是否有左子节点</span></span><br><span class="line">			<span class="keyword">if</span> (node.left === <span class="literal">null</span>) &#123;</span><br><span class="line">				<span class="comment">// 设置这个新节点为左子节点</span></span><br><span class="line">				node.left = newNode</span><br><span class="line">			&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">				<span class="comment">// 递归，继承用新节点和左子节点比较</span></span><br><span class="line">				node.left = <span class="keyword">this</span>._insert(node.left, newNode)</span><br><span class="line"></span><br><span class="line">				<span class="comment">// 重新检查并调整当前这个节点的平衡</span></span><br><span class="line">				node = <span class="keyword">this</span>.keepBalance(node)</span><br><span class="line">			&#125;</span><br><span class="line">		&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">			<span class="comment">// 判断是否有右子节点</span></span><br><span class="line">			<span class="keyword">if</span> (node.right === <span class="literal">null</span>) &#123;</span><br><span class="line">				<span class="comment">// 设置这个新节点为右子节点</span></span><br><span class="line">				node.right = newNode</span><br><span class="line">			&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">				<span class="comment">// 递归，继承用新节点和右子节点比较</span></span><br><span class="line">				node.right = <span class="keyword">this</span>._insert(node.right, newNode)</span><br><span class="line"></span><br><span class="line">				<span class="comment">// 重新检查并调整当前这个节点的平衡</span></span><br><span class="line">				node = <span class="keyword">this</span>.keepBalance(node)</span><br><span class="line">			&#125;</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">return</span> node</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">// 判断树中是否包含某一个数</span></span><br><span class="line">	has(data) &#123;</span><br><span class="line">		<span class="comment">// 从根节点开始查找</span></span><br><span class="line">		<span class="keyword">return</span> <span class="keyword">this</span>._has(<span class="keyword">this</span>.root, data)</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	_has(node, data) &#123;</span><br><span class="line">		<span class="comment">// 如果节点为空，说明树中没有这个数</span></span><br><span class="line">		<span class="keyword">if</span> (node == <span class="literal">null</span>) &#123;</span><br><span class="line">			<span class="keyword">return</span> <span class="literal">false</span></span><br><span class="line">		&#125;</span><br><span class="line">		<span class="comment">// 如果值和前节点值相同，找到了</span></span><br><span class="line">		<span class="keyword">if</span> (data == node.data) &#123;</span><br><span class="line">			<span class="keyword">return</span> <span class="literal">true</span></span><br><span class="line">		&#125; <span class="keyword">else</span> <span class="keyword">if</span> (data &lt; node.data) &#123;</span><br><span class="line">			<span class="comment">// 到左子树中查找</span></span><br><span class="line">			<span class="keyword">return</span> <span class="keyword">this</span>._has(node.left, data)</span><br><span class="line">		&#125; <span class="keyword">else</span> <span class="keyword">if</span> (data &gt; node.data) &#123;</span><br><span class="line">			<span class="comment">// 到右子树中查找</span></span><br><span class="line">			<span class="keyword">return</span> <span class="keyword">this</span>._has(node.right, data)</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">// 前序遍历（根左右）</span></span><br><span class="line">	preOrder() &#123;</span><br><span class="line">		<span class="keyword">this</span>._preOrder(<span class="keyword">this</span>.root)</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">// 开始的节点</span></span><br><span class="line">	_preOrder(node) &#123;</span><br><span class="line">		<span class="keyword">if</span> (node === <span class="literal">null</span>) <span class="keyword">return</span></span><br><span class="line">		<span class="comment">// 根</span></span><br><span class="line">		<span class="built_in">console</span>.log(node.data)</span><br><span class="line">		<span class="comment">// 左</span></span><br><span class="line">		<span class="keyword">this</span>._preOrder(node.left)</span><br><span class="line">		<span class="comment">// 右</span></span><br><span class="line">		<span class="keyword">this</span>._preOrder(node.right)</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">// 中序遍历（左根右）</span></span><br><span class="line">	midOrder() &#123;</span><br><span class="line">		<span class="keyword">this</span>._midOrder(<span class="keyword">this</span>.root)</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">// 开始的节点</span></span><br><span class="line">	_midOrder(node) &#123;</span><br><span class="line">		<span class="keyword">if</span> (node === <span class="literal">null</span>) <span class="keyword">return</span></span><br><span class="line">		<span class="comment">// 左</span></span><br><span class="line">		<span class="keyword">this</span>._midOrder(node.left)</span><br><span class="line">		<span class="comment">// 根</span></span><br><span class="line">		<span class="built_in">console</span>.log(node.data)</span><br><span class="line">		<span class="comment">// 右</span></span><br><span class="line">		<span class="keyword">this</span>._midOrder(node.right)</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">// 后序遍历（左右根）</span></span><br><span class="line">	postOrder() &#123;</span><br><span class="line">		<span class="keyword">this</span>._postOrder(<span class="keyword">this</span>.root)</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">// 开始的节点</span></span><br><span class="line">	_postOrder(node) &#123;</span><br><span class="line">		<span class="keyword">if</span> (node === <span class="literal">null</span>) <span class="keyword">return</span></span><br><span class="line">		<span class="comment">// 左</span></span><br><span class="line">		<span class="keyword">this</span>._postOrder(node.left)</span><br><span class="line">		<span class="comment">// 右</span></span><br><span class="line">		<span class="keyword">this</span>._postOrder(node.right)</span><br><span class="line">		<span class="comment">// 根</span></span><br><span class="line">		<span class="built_in">console</span>.log(node.data)</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">// 层序遍历</span></span><br><span class="line">	layerOrder() &#123;</span><br><span class="line">		<span class="comment">// 1. 创建一个队列（先入先出）</span></span><br><span class="line">		<span class="keyword">let</span> queue = []</span><br><span class="line">		<span class="comment">// 2. 先根节点放到队尾</span></span><br><span class="line">		queue.push(<span class="keyword">this</span>.root)</span><br><span class="line">		<span class="comment">// 3. 循环队列</span></span><br><span class="line">		<span class="keyword">let</span> node</span><br><span class="line">		<span class="keyword">while</span> (queue.length &gt; <span class="number">0</span>) &#123;</span><br><span class="line">			<span class="comment">// 4. 从队头取出节点</span></span><br><span class="line">			node = queue.shift()</span><br><span class="line">			<span class="comment">// 5. 左右子节点放入队尾</span></span><br><span class="line">			<span class="keyword">if</span> (node.left !== <span class="literal">null</span>) queue.push(node.left)</span><br><span class="line">			<span class="keyword">if</span> (node.right !== <span class="literal">null</span>) queue.push(node.right)</span><br><span class="line">			<span class="comment">// 6. 输出当前节点（使用这个节点）</span></span><br><span class="line">			<span class="built_in">console</span>.log(node.data)</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">// 获取节点高度</span></span><br><span class="line">	getHeight(node) &#123;</span><br><span class="line">		<span class="keyword">if</span> (node === <span class="literal">null</span>) <span class="keyword">return</span> <span class="number">0</span></span><br><span class="line">		<span class="comment">// 左右节点中最长的边数</span></span><br><span class="line">		<span class="keyword">return</span> <span class="built_in">Math</span>.max(<span class="keyword">this</span>.getHeight(node.left), <span class="keyword">this</span>.getHeight(node.right)) + <span class="number">1</span></span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">// 左旋转</span></span><br><span class="line">	rotateToL(node) &#123;</span><br><span class="line">		<span class="comment">// 1. 取出右子节点（C）</span></span><br><span class="line">		<span class="keyword">let</span> tmp = node.right</span><br><span class="line">		<span class="comment">// 2. 父节点指向右子节点的左子节点</span></span><br><span class="line">		node.right = tmp.left</span><br><span class="line">		<span class="comment">// 3. 右子节点的左子节点指向父节点</span></span><br><span class="line">		tmp.left = node</span><br><span class="line">		<span class="comment">// 4. 返回新的顶点</span></span><br><span class="line">		<span class="keyword">return</span> tmp</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">// 右旋转</span></span><br><span class="line">	rotateToR(node) &#123;</span><br><span class="line">		<span class="keyword">let</span> tmp = node.left</span><br><span class="line">		node.left = tmp.right</span><br><span class="line">		tmp.right = node</span><br><span class="line">		<span class="keyword">return</span> tmp</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">// 先左旋再右旋转</span></span><br><span class="line">	rorateToLR(node) &#123;</span><br><span class="line">		<span class="comment">// 让左子节点左旋转，并让旋转之后的顶点做为左子节点</span></span><br><span class="line">		node.left = <span class="keyword">this</span>.rotateToL(node.left)</span><br><span class="line">		<span class="comment">// 再让当前节点右旋转</span></span><br><span class="line">		<span class="keyword">return</span> <span class="keyword">this</span>.rotateToR(node)</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">// 先右旋转再左旋转</span></span><br><span class="line">	rotateToRL(node) &#123;</span><br><span class="line">		<span class="comment">// 让右子节点先右旋转，并用新的顶点做为右子节点</span></span><br><span class="line">		node.right = <span class="keyword">this</span>.rotateToR(node.right)</span><br><span class="line">		<span class="comment">// 当前节点左旋</span></span><br><span class="line">		<span class="keyword">return</span> <span class="keyword">this</span>.rotateToL(node)</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">// 调整二叉树为平衡状态</span></span><br><span class="line">	keepBalance(node) &#123;</span><br><span class="line">		<span class="keyword">if</span>(node === <span class="literal">null</span>) <span class="keyword">return</span> node</span><br><span class="line">		<span class="comment">// 1. 计算左右子节点的高度</span></span><br><span class="line">		<span class="keyword">let</span> leftHeight = <span class="keyword">this</span>.getHeight(node.left)</span><br><span class="line">		<span class="keyword">let</span> rightHeight = <span class="keyword">this</span>.getHeight(node.right)</span><br><span class="line">		<span class="comment">// 2. 判断是否不平衡，并判断是 L 型还是 R 型</span></span><br><span class="line">		<span class="keyword">if</span> (leftHeight - rightHeight &gt; <span class="number">1</span>) &#123; <span class="comment">// L 型</span></span><br><span class="line">			<span class="comment">// 3. 判断左子节点的左右谁高</span></span><br><span class="line">			<span class="keyword">if</span> (<span class="keyword">this</span>.getHeight(node.left.left) &gt;= <span class="keyword">this</span>.getHeight(node.left.right)) &#123; <span class="comment">// L 型</span></span><br><span class="line">				<span class="comment">// LL型-》右旋转</span></span><br><span class="line">				node = <span class="keyword">this</span>.rotateToR(node)</span><br><span class="line">			&#125; <span class="keyword">else</span> &#123; <span class="comment">// R 型</span></span><br><span class="line">				<span class="comment">// LR开进：先左旋转，再右旋转</span></span><br><span class="line">				node = <span class="keyword">this</span>.rorateToLR(node)</span><br><span class="line">			&#125;</span><br><span class="line">		&#125; <span class="keyword">else</span> <span class="keyword">if</span> (rightHeight - leftHeight &gt; <span class="number">1</span>) &#123; <span class="comment">// R 型</span></span><br><span class="line">			<span class="comment">// 4. 判断右子节点的左右谁高</span></span><br><span class="line">			<span class="keyword">if</span> (<span class="keyword">this</span>.getHeight(node.right.left) &gt;= <span class="keyword">this</span>.getHeight(node.right.right)) &#123; <span class="comment">// L</span></span><br><span class="line">				<span class="comment">// RL型 -》先右旋转再左旋转</span></span><br><span class="line">				node = <span class="keyword">this</span>.rotateToRL(node)</span><br><span class="line">			&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">				<span class="comment">// RR型-》左旋转</span></span><br><span class="line">				node = <span class="keyword">this</span>.rotateToL(node)</span><br><span class="line">			&#125;</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">return</span> node</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">// 删除数据</span></span><br><span class="line">	deleteNode(data) &#123;</span><br><span class="line">		<span class="comment">// 从根开始比较删除</span></span><br><span class="line">		<span class="keyword">this</span>.root = <span class="keyword">this</span>._deleteNode(<span class="keyword">this</span>.root, data)</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	_deleteNode(node, data) &#123;</span><br><span class="line"></span><br><span class="line">		<span class="comment">// 没有子节点了，不用删除</span></span><br><span class="line">		<span class="keyword">if</span> (node == <span class="literal">null</span>) <span class="keyword">return</span> <span class="literal">null</span></span><br><span class="line"></span><br><span class="line">		<span class="keyword">if</span> (data &lt; node.data) &#123;</span><br><span class="line">			<span class="comment">// 往左走</span></span><br><span class="line">			node.left = <span class="keyword">this</span>._deleteNode(node.left, data)</span><br><span class="line">			<span class="comment">// 重新调整节点的平衡</span></span><br><span class="line">			<span class="keyword">return</span> <span class="keyword">this</span>.keepBalance(node)</span><br><span class="line">		&#125; <span class="keyword">else</span> <span class="keyword">if</span> (data &gt; node.data) &#123;</span><br><span class="line">			<span class="comment">// 往右走</span></span><br><span class="line">			node.right = <span class="keyword">this</span>._deleteNode(node.right, data)</span><br><span class="line">			<span class="comment">// 重新调整节点 平衡</span></span><br><span class="line">			<span class="keyword">return</span> <span class="keyword">this</span>.keepBalance(node)</span><br><span class="line">		&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">			<span class="comment">// 如果相等就是找到了节点位置 ，要删除当前节点</span></span><br><span class="line">			<span class="comment">// 情况一、有两个子节点</span></span><br><span class="line">			<span class="keyword">if</span> (node.left !== <span class="literal">null</span> &amp;&amp; node.right !== <span class="literal">null</span>) &#123;</span><br><span class="line">				</span><br><span class="line">				<span class="comment">// 取出右子节点</span></span><br><span class="line">				<span class="keyword">let</span> tmp = node.right</span><br><span class="line"></span><br><span class="line">				<span class="comment">// 找出最小的节点（最左边的分支）</span></span><br><span class="line">				<span class="keyword">while</span> (tmp.left !== <span class="literal">null</span>) &#123;</span><br><span class="line">					tmp = tmp.left</span><br><span class="line">				&#125;</span><br><span class="line"></span><br><span class="line">				<span class="comment">// 把最小的值赋给当前节点</span></span><br><span class="line">				node.data = tmp.data</span><br><span class="line"></span><br><span class="line">				<span class="comment">// 从右分支中删除这个最小的节点</span></span><br><span class="line">				node.right = <span class="keyword">this</span>._deleteNode(<span class="keyword">this</span>.right, tmp.data)</span><br><span class="line">				<span class="comment">// 重新调整平衡</span></span><br><span class="line">				node = <span class="keyword">this</span>.keepBalance(node)</span><br><span class="line"></span><br><span class="line">				<span class="keyword">return</span> node</span><br><span class="line"></span><br><span class="line">			&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">				<span class="comment">// 情况二、没有子节点</span></span><br><span class="line">				<span class="keyword">if</span> (node.left === <span class="literal">null</span> &amp;&amp; node.right === <span class="literal">null</span>) &#123;</span><br><span class="line">					node = <span class="literal">null</span></span><br><span class="line">					<span class="keyword">return</span> <span class="literal">null</span></span><br><span class="line">				&#125;</span><br><span class="line"></span><br><span class="line">				<span class="comment">// 情况三、只有左节点</span></span><br><span class="line">				<span class="keyword">if</span> (node.left !== <span class="literal">null</span>) &#123;</span><br><span class="line">					<span class="comment">// 左节点替换当前节点</span></span><br><span class="line">					node = node.left</span><br><span class="line">					<span class="keyword">return</span> node</span><br><span class="line">				&#125;</span><br><span class="line"></span><br><span class="line">				<span class="comment">// 情况四、只有右节点</span></span><br><span class="line">				<span class="keyword">if</span> (node.right !== <span class="literal">null</span>) &#123;</span><br><span class="line">					<span class="comment">// 右节点替换当前节点</span></span><br><span class="line">					node = node.right</span><br><span class="line">					<span class="keyword">return</span> node</span><br><span class="line">				&#125;</span><br><span class="line">			&#125;</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">	</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> avl = <span class="keyword">new</span> AVLTree()</span><br><span class="line">avl.insert(<span class="number">3</span>)</span><br><span class="line">avl.insert(<span class="number">2</span>)</span><br><span class="line">avl.insert(<span class="number">1</span>)</span><br><span class="line">avl.insert(<span class="number">4</span>)</span><br><span class="line">avl.insert(<span class="number">5</span>)</span><br><span class="line"></span><br><span class="line">avl.deleteNode(<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(avl.root)</span><br></pre></td></tr></table></figure><br><h3 id="红黑树"><a href="#红黑树" class="headerlink" title="红黑树"></a>红黑树</h3><blockquote><p>引自：<a href="https://www.jianshu.com/p/bad1e3f26466" target="_blank" rel="noopener">https://www.jianshu.com/p/bad1e3f26466</a></p></blockquote><p>红黑树是一种非完美平衡的自平衡二叉树，在搜索时经常使用，它有以下五个规则：</p><ul><li>所有节点都有颜色，要么是红色，要么是黑色</li><li>根节点是黑色的</li><li>所有空节点（NIL）都是黑色的空节点</li><li>红色节点的子节点必须是黑色的(红色节点不能连续）</li><li>任何一个节点到它的叶子节点包含相同的黑色节点</li></ul><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gexxl3mbctj30ti0jo7mf.jpg" alt="image.png"></p><br><h3 id="AVL和红黑树的区别"><a href="#AVL和红黑树的区别" class="headerlink" title="AVL和红黑树的区别"></a>AVL和红黑树的区别</h3><blockquote><p>引用：<a href="https://www.cnblogs.com/ajianbeyourself/p/11173851.html" target="_blank" rel="noopener">https://www.cnblogs.com/ajianbeyourself/p/11173851.html</a></p></blockquote><br><h2 id="堆"><a href="#堆" class="headerlink" title="堆"></a>堆</h2><h3 id="介绍-8"><a href="#介绍-8" class="headerlink" title="介绍"></a>介绍</h3><p>堆（Heap）是一种特殊的二叉树：</p><ol><li>堆是一个完全二叉树</li><li>堆中每一个节点的值都必须大于等于（或小于等于）其子树中的每个节点的值</li></ol><h3 id="分类-1"><a href="#分类-1" class="headerlink" title="分类"></a>分类</h3><p>堆分为两种：<code>大顶堆</code> 和 <code>小顶堆</code> 。</p><ul><li>大顶堆：父顶点的值大于所有子顶点的值。</li><li>小顶堆：父顶点的值小于所有子顶点的值。</li></ul><p>大顶堆：</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gexxu4h7etj30be08gmxx.jpg" alt="image.png"></p><p>小顶堆：</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gexxujf9kcj30p00cqgoi.jpg" alt="image.png"></p><h3 id="存储"><a href="#存储" class="headerlink" title="存储"></a>存储</h3><p>堆是一种二叉树，有两种存储方式：</p><ul><li>数组</li><li>链表</li></ul><p>堆是一种完全二叉树，而完全二叉树使用 <code>数组</code> 存储比较合适。</p><p><img src="https://img.kancloud.cn/36/7c/367c25251bdf4400bc285f53280b1b6e_1166x814.png" alt="img"></p><p>当以数组保存二叉树时有以下几个重要公式。</p><ol><li>对于下标为 i 节点（子节点）<br>左子节点下标：2i+1<br>右子节点下标：2i+2</li><li>对于下标为 i 的节点（父节点）<br>父节点下标：Math.floor( (i-1) / 2 )</li><li>最后一个非叶子节点的节点的下标<br>Math.floor(len/2) - 1</li></ol><h3 id="应用场景-2"><a href="#应用场景-2" class="headerlink" title="应用场景"></a>应用场景</h3><ol><li>排序 —》 堆排序（时间复杂度：O(nlogn)</li><li>优先队列（优先级高的放到前面）</li></ol><h3 id="操作"><a href="#操作" class="headerlink" title="操作"></a>操作</h3><p>二叉堆的操作有三种：</p><ul><li>插入节点</li><li>删除节点</li><li>构建二叉堆</li></ul><h4 id="插入节点"><a href="#插入节点" class="headerlink" title="插入节点"></a>插入节点</h4><p>当向二叉堆中插入新节点时的操作：</p><ol><li>将新节点先放到 <code>最后</code></li><li>然后依次和父节点比较，然后 <code>上浮</code></li></ol><p>如，插入0：</p><ol><li>插入到最后</li></ol><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gexxvwe8buj30ve0p8nb5.jpg" alt="image.png"></p><ol start="2"><li>和父节点比较并上浮</li></ol><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gexxwedocoj30vc0ok7ie.jpg" alt="image.png"></p><ol start="3"><li>和父节点比较并上浮</li></ol><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gexxwzncknj30w00oq4d0.jpg" alt="image.png"></p><ol start="4"><li>继续比较上浮</li></ol><p><img src="https://img.kancloud.cn/2e/51/2e51c02ed76614e2f7b1d980e87f8ea1_1140x910.png" alt="img"></p><h4 id="删除节点"><a href="#删除节点" class="headerlink" title="删除节点"></a>删除节点</h4><p>删除节点时，一般就是删除堆是根节点，过程和插入节点正好相反：</p><ol><li>删除顶节点</li><li>将最后一个节点拿到父节点</li><li>和子节点比较并 <code>下沉</code></li></ol><p>比如，删除 1</p><ol><li>删除节点</li></ol><p><img src="https://img.kancloud.cn/c3/97/c397773fae8ae6618c2a2561d9a8b5fa_1158x920.png" alt="img"></p><ol start="2"><li>将最后一个节点临时拿到根节点的位置</li></ol><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gexxz8nzl2j30vg0pk16h.jpg" alt="image.png"></p><ol start="3"><li>和左右子节点比较，让最小的节点上来，它下沉</li></ol><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gexxzuuiqbj30ve0pak57.jpg" alt="image.png"></p><ol start="4"><li>继续和子节点比较并下沉</li></ol><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gexy2hlcg5j30v20powt2.jpg" alt="image.png"></p><h4 id="构建二叉堆"><a href="#构建二叉堆" class="headerlink" title="构建二叉堆"></a>构建二叉堆</h4><p><a href="https://www.kancloud.cn/fortheday/js-data-structure-and-algorithm/1698048" target="_blank" rel="noopener">排序</a>从最后一个 <code>非叶子节点 Math.floor(数组长度/2)-1</code> 开始比较并 （大/小）上浮。</p><ol><li>比较有以下堆</li></ol><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gexy3j0fy7j30kw0i2tes.jpg" alt="image.png"></p><ol start="2"><li><p>从最后一个非叶子节点开始比较</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gexy45356nj30n209678c.jpg" alt="image.png"></p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gexy4m0ai3j30se0mmn7l.jpg" alt="image.png"></p></li></ol><h3 id="代码实现-2"><a href="#代码实现-2" class="headerlink" title="代码实现"></a>代码实现</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 小顶堆</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SmallHeap</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">constructor</span>() &#123;</span><br><span class="line">    <span class="comment">// 初始化一个保存数据的数组</span></span><br><span class="line">    <span class="keyword">this</span>.arr = []</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 向堆中放数据</span></span><br><span class="line">  push(data) &#123;</span><br><span class="line">    <span class="comment">// 1. 先将数据放到堆尾</span></span><br><span class="line">    <span class="keyword">this</span>.arr.push(data)</span><br><span class="line">    <span class="comment">// 2. 上浮（依次和父节点进行比较）</span></span><br><span class="line">    <span class="comment">// 2.1 获取当前这个新元素的下标</span></span><br><span class="line">    <span class="keyword">let</span> current = <span class="keyword">this</span>.arr.length - <span class="number">1</span></span><br><span class="line">    <span class="comment">// 2.2 父元素的下标 </span></span><br><span class="line">    <span class="keyword">let</span> parent = <span class="built_in">Math</span>.floor((current - <span class="number">1</span>) / <span class="number">2</span>)</span><br><span class="line">    <span class="comment">// 2.3 循环一直找父节点</span></span><br><span class="line">    <span class="keyword">while</span> (parent &gt;= <span class="number">0</span>) &#123;</span><br><span class="line">      <span class="comment">// 2.4 和父节点比较</span></span><br><span class="line">      <span class="keyword">if</span> (<span class="keyword">this</span>.arr[current] &lt; <span class="keyword">this</span>.arr[parent]) &#123;</span><br><span class="line">        <span class="comment">// 2.5 交换</span></span><br><span class="line">        [<span class="keyword">this</span>.arr[current], <span class="keyword">this</span>.arr[parent]] = [<span class="keyword">this</span>.arr[parent], <span class="keyword">this</span>.arr[current]]</span><br><span class="line">        <span class="comment">// 2.6 当前节点的下标变成父节点的下标</span></span><br><span class="line">        current = parent</span><br><span class="line">        <span class="comment">// 2.7 重新计算新的父节点</span></span><br><span class="line">        parent = <span class="built_in">Math</span>.floor((current - <span class="number">1</span>) / <span class="number">2</span>)</span><br><span class="line">      &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="comment">// 2.8 如果当前节点大就退出循环</span></span><br><span class="line">        <span class="keyword">break</span></span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 弹出堆顶元素</span></span><br><span class="line">  pop() &#123;</span><br><span class="line">    <span class="comment">// 1. 获取堆顶元素的值</span></span><br><span class="line">    <span class="keyword">let</span> value = <span class="keyword">this</span>.arr[<span class="number">0</span>]</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 2. 获取数组中最后一个元素的值，并将这个值从数组中删除</span></span><br><span class="line">    <span class="keyword">let</span> lastValue = <span class="keyword">this</span>.arr.pop()</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 3. 最后一个值替换第1个元素</span></span><br><span class="line">    <span class="keyword">this</span>.arr[<span class="number">0</span>] = lastValue</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 4. 和子节点比较然后进行下沉</span></span><br><span class="line">    <span class="comment">// 4.1 当前节点的下标</span></span><br><span class="line">    <span class="keyword">let</span> current = <span class="number">0</span></span><br><span class="line">    <span class="comment">// 4.2 左、右子节点的下标</span></span><br><span class="line">    <span class="keyword">let</span> left = <span class="number">2</span> * current + <span class="number">1</span></span><br><span class="line">    <span class="keyword">let</span> right = <span class="number">2</span> * current + <span class="number">2</span></span><br><span class="line">    <span class="keyword">let</span> smallest = <span class="number">0</span> <span class="comment">// 最小元素的下标</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 如果有子节点就向下比较</span></span><br><span class="line">    <span class="keyword">while</span> (left &lt; <span class="keyword">this</span>.arr.length) &#123;</span><br><span class="line">      <span class="comment">// 4.3 比左子节点大</span></span><br><span class="line">      <span class="keyword">if</span> (<span class="keyword">this</span>.arr[current] &gt; <span class="keyword">this</span>.arr[left]) &#123;</span><br><span class="line">        <span class="comment">// 左子节点和右子节点的大小</span></span><br><span class="line">        <span class="keyword">if</span> (<span class="keyword">this</span>.arr[left] &gt; <span class="keyword">this</span>.arr[right]) &#123;</span><br><span class="line">          <span class="comment">// 右边最小</span></span><br><span class="line">          smallest = right</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">          <span class="comment">// 左边最小</span></span><br><span class="line">          smallest = left</span><br><span class="line">        &#125;</span><br><span class="line">      &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="comment">// 当前节点小于左子节点</span></span><br><span class="line">        <span class="comment">// 判断和右子节点的大小</span></span><br><span class="line">        <span class="keyword">if</span> (<span class="keyword">this</span>.arr[current] &lt;= <span class="keyword">this</span>.arr[right]) &#123;</span><br><span class="line">          <span class="comment">// 退出循环</span></span><br><span class="line">          <span class="keyword">break</span></span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">          smallest = right</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="comment">// 最小元素的下标和当前元素下标是否相等</span></span><br><span class="line">      <span class="keyword">if</span> (current === smallest) &#123;</span><br><span class="line">        <span class="keyword">break</span></span><br><span class="line">      &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="comment">// 当前元素和最小元素进行交换</span></span><br><span class="line">        [<span class="keyword">this</span>.arr[current], <span class="keyword">this</span>.arr[smallest]] = [<span class="keyword">this</span>.arr[smallest], <span class="keyword">this</span>.arr[current]]</span><br><span class="line">        <span class="comment">// 修改相关下标</span></span><br><span class="line">        current = smallest  <span class="comment">// 当前下标变成交换之后最小的下标</span></span><br><span class="line">        <span class="comment">// 重新计算左右子节点下标 </span></span><br><span class="line">        left = <span class="number">2</span> * current + <span class="number">1</span></span><br><span class="line">        right = <span class="number">2</span> * current + <span class="number">2</span></span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> value</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> smH = <span class="keyword">new</span> SmallHeap()</span><br><span class="line">smH.push(<span class="number">10</span>)</span><br><span class="line">smH.push(<span class="number">5</span>)</span><br><span class="line">smH.push(<span class="number">2</span>)</span><br><span class="line">smH.push(<span class="number">8</span>)</span><br><span class="line">smH.push(<span class="number">1</span>)</span><br><span class="line">smH.push(<span class="number">4</span>)</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(smH.arr)</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(smH.pop())</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(smH.arr)</span><br></pre></td></tr></table></figure><br><h2 id="哈夫曼编码"><a href="#哈夫曼编码" class="headerlink" title="哈夫曼编码"></a>哈夫曼编码</h2><h3 id="几个概念"><a href="#几个概念" class="headerlink" title="几个概念"></a>几个概念</h3><h4 id="路径"><a href="#路径" class="headerlink" title="路径"></a>路径</h4><p>在一棵树中，从一个结点到另一个结点所经过的所有结点，被我们称为两个结点之间的路径。<br>比如：A -&gt; H 的路径：</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gey0mh1sylj30yc0u4h3f.jpg" alt="image.png"></p><h4 id="路径长度"><a href="#路径长度" class="headerlink" title="路径长度"></a>路径长度</h4><p>在一棵树中，从一个结点到另一个结点所经过的“边”的数量，被我们称为两个结点之间的路径长度。<br>比如：A -&gt; H的路径长度为 3：</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gey0n00x1nj30xs0twdym.jpg" alt="image.png"></p><h4 id="节点的带权路径长度"><a href="#节点的带权路径长度" class="headerlink" title="节点的带权路径长度"></a>节点的带权路径长度</h4><p>每一个节点都可以有一个权重（数字）。<br>带权路径长度：节点权重 * 节点到根节点的路径长度<br>比如：H 的带权路径长度 = 3 * 3 = 9</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gey0njwevoj30yo0vc1bc.jpg" alt="image.png"></p><h4 id="树的带权路径长度"><a href="#树的带权路径长度" class="headerlink" title="树的带权路径长度"></a>树的带权路径长度</h4><p>树的带权路径长度（也做WPL）：所有 <code>叶子</code> 节点的带权路径长度之和。<br>比如：下面这棵树的 WPL = 3<em>3 + 6</em>3 + 1<em>2 + 4</em>2 + 8*2 = 53</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gey0nx7lh9j30xw0vw7mo.jpg" alt="image.png"></p><h4 id="哈夫曼树"><a href="#哈夫曼树" class="headerlink" title="哈夫曼树"></a>哈夫曼树</h4><p>哈夫曼树（Huffman Tree）：是在叶子结点和权重确定的情况下，带权路径长度最小的二叉树，也被称为最优二叉树。<br>比如下图左侧就比右侧 WPL 小。</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gey0oe05d6j30xm0h8wlu.jpg" alt="image.png"></p><h4 id="哈夫曼编码-1"><a href="#哈夫曼编码-1" class="headerlink" title="哈夫曼编码"></a>哈夫曼编码</h4><p>哈夫曼编码可以用来进行 <code>数据压缩</code> 。</p><h5 id="编码"><a href="#编码" class="headerlink" title="编码"></a>编码</h5><p>比如要压缩：“acbcbacddaddaddccd”</p><ol><li>先统计文本中每个字符出现的频率</li></ol><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gey0ov2ji6j30dy0e23z3.jpg" alt="image.png"></p><ol start="2"><li>频率当作权重构建哈夫曼树</li></ol><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gey0ph84irj30hs0p4tdx.jpg" alt="image.png"></p><ol start="3"><li>根据哈夫曼树对字符串进行编码</li></ol><p>编码规则：</p><ol><li>左子节点是0，右子节点是1</li><li>从根节点到叶子结果</li></ol><p>根据哈夫曼树可以将字符串编码为：</p><ul><li>a:111</li><li>ac:1111 0</li><li>acb:1111 0110</li><li>acbc:1111 011010</li><li>acbcb:1111 0110 1011 0…</li></ul><h5 id="解码"><a href="#解码" class="headerlink" title="解码"></a>解码</h5><p>编码过程就是：</p><ol><li>将哈夫曼编码到哈夫曼树上 “从根向下跑一遍”</li><li>0 向左、 1 向右</li><li>当遇到一个 “叶子” 节点时结束</li><li>重复从根开始跑，重复 1~3</li></ol><p>比如：1111 0110 1011 0… 到树上跑得到：acbcb</p><h3 id="构建哈夫曼树的流程"><a href="#构建哈夫曼树的流程" class="headerlink" title="构建哈夫曼树的流程"></a>构建哈夫曼树的流程</h3><ol><li>将带权节点 <code>按升序</code> 放到数组中</li></ol><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gey0qv0kywj306o0pyjst.jpg" alt="image.png"></p><ol start="2"><li>取出数组中最小的两个节点做为子节点构造一棵树，和为父节点</li></ol><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gey0rdxiylj30k80rqq80.jpg" alt="image.png"></p><ol start="3"><li>将父节点的值放回数组中并 <code>排序</code></li></ol><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gey0rvpbhrj30je0l2tcm.jpg" alt="image.png"></p><ol start="4"><li>重复2~3步骤<br>拿出最小两个节点：</li></ol><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gey0sm7en0j30m80ly449.jpg" alt="image.png"></p><p>将的父节点放回并排序</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gey0t3vh63j30ma0k4n3o.jpg" alt="image.png"></p><ol start="5"><li>重复2~3</li></ol><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gey0tle9p5j30n40miwmi.jpg" alt="image.png"></p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gey0trzj0yj30ma0kowlf.jpg" alt="image.png"></p><ol start="6"><li>重复2~3</li></ol><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gey0ug9eakj30qm0p8thh.jpg" alt="image.png"></p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gey0uqsiaqj30ru0q2the.jpg" alt="image.png"></p><ol start="7"><li>重复2~3</li></ol><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gey0v56aj7j30xw0vmtk7.jpg" alt="image.png"></p><p><img src="https://img.kancloud.cn/0b/1f/0b1f9c52ef4b2e234cbc8b1c9923800f_1200x1156.png" alt="img"></p><p>最后数组中只剩下一个节点，说明构造结束！</p><h3 id="代码实现-构造哈夫曼树"><a href="#代码实现-构造哈夫曼树" class="headerlink" title="代码实现-构造哈夫曼树"></a>代码实现-构造哈夫曼树</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 定义节点类</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Node</span> </span>&#123;</span><br><span class="line">    <span class="keyword">constructor</span>(data) &#123;</span><br><span class="line">        <span class="keyword">this</span>.data = data</span><br><span class="line">        <span class="keyword">this</span>.left = <span class="literal">null</span>    <span class="comment">// 左子节点</span></span><br><span class="line">        <span class="keyword">this</span>.right = <span class="literal">null</span>   <span class="comment">// 右子节点</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">HuffmanTree</span> </span>&#123;</span><br><span class="line">    <span class="keyword">constructor</span>(arr) &#123;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">this</span>.root = <span class="literal">null</span> <span class="comment">// 树根节点</span></span><br><span class="line"></span><br><span class="line">        <span class="keyword">while</span> (arr.length &gt; <span class="number">1</span>) &#123;</span><br><span class="line">            <span class="comment">// 1. 排序（升序）</span></span><br><span class="line">            arr.sort(<span class="function">(<span class="params">x, y</span>) =&gt;</span> x - y)</span><br><span class="line">            <span class="comment">// 2. 取出前两个</span></span><br><span class="line">            <span class="keyword">let</span> first = arr.shift()</span><br><span class="line">            <span class="keyword">let</span> second = arr.shift()</span><br><span class="line">            <span class="comment">// 3. 求和</span></span><br><span class="line">            <span class="keyword">let</span> parent = first + second</span><br><span class="line">            <span class="comment">// 4. 构造子树</span></span><br><span class="line">            arr.unshift(parent)</span><br><span class="line">            <span class="comment">// 5. 父节点放回数组</span></span><br><span class="line">            <span class="comment">// 5.1 先创建三个节点</span></span><br><span class="line">            first = <span class="keyword">new</span> Node(first)</span><br><span class="line">            second = <span class="keyword">new</span> Node(second)</span><br><span class="line">            parent = <span class="keyword">new</span> Node(parent)</span><br><span class="line"></span><br><span class="line">            <span class="comment">// 还没有树时，直接创建小树</span></span><br><span class="line">            <span class="keyword">if</span> (<span class="keyword">this</span>.root == <span class="literal">null</span>) &#123;</span><br><span class="line">                <span class="comment">// 5.2 关系</span></span><br><span class="line">                parent.left = first</span><br><span class="line">                parent.right = second</span><br><span class="line"></span><br><span class="line">                <span class="comment">// 5.3 设置根节点</span></span><br><span class="line">                <span class="keyword">this</span>.root = parent</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="comment">// 如果已经有一颗小树了</span></span><br><span class="line">                <span class="comment">// 第1个元素和现在这棵树的根节点是否相同</span></span><br><span class="line">                <span class="keyword">if</span> (first.data == <span class="keyword">this</span>.root.data) &#123;</span><br><span class="line">                    <span class="comment">// 当原小树当作新父节点的左子节点</span></span><br><span class="line">                    parent.left = <span class="keyword">this</span>.root</span><br><span class="line">                    <span class="comment">// 当这个父节点成为新的跟节点</span></span><br><span class="line">                    <span class="keyword">this</span>.root = parent</span><br><span class="line">                    <span class="comment">// 右子节点是第二个元素</span></span><br><span class="line">                    <span class="keyword">this</span>.root.right = second</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    <span class="comment">// 原树根成为父节点的右子节点</span></span><br><span class="line">                    parent.right = <span class="keyword">this</span>.root</span><br><span class="line">                    <span class="comment">// 当这个父节点成为新的跟节点</span></span><br><span class="line">                    <span class="keyword">this</span>.root = parent</span><br><span class="line">                    <span class="comment">// 左子节点是第一个元素</span></span><br><span class="line">                    <span class="keyword">this</span>.root.left = first</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 构造哈夫曼树</span></span><br><span class="line"><span class="keyword">let</span> data = [<span class="number">3</span>, <span class="number">2</span>, <span class="number">7</span>, <span class="number">18</span>, <span class="number">25</span>, <span class="number">9</span>]</span><br><span class="line"><span class="keyword">let</span> ht = <span class="keyword">new</span> HuffmanTree(data)</span><br><span class="line"><span class="built_in">console</span>.log(ht.root);</span><br></pre></td></tr></table></figure><br><h1 id="图"><a href="#图" class="headerlink" title="图"></a>图</h1><h2 id="介绍-9"><a href="#介绍-9" class="headerlink" title="介绍"></a>介绍</h2><p>多对多的一种数据结构。</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gez6f6743dj30xy0l2qct.jpg" alt="image.png"></p><h3 id="术语"><a href="#术语" class="headerlink" title="术语"></a>术语</h3><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gez6fwzp4dj30y40x0aox.jpg" alt="image.png"></p><h2 id="分类-2"><a href="#分类-2" class="headerlink" title="分类"></a>分类</h2><h3 id="有向图和无向图"><a href="#有向图和无向图" class="headerlink" title="有向图和无向图"></a>有向图和无向图</h3><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gez6qbzpdmj30rc0astax.jpg" alt="image.png"></p><h3 id="有权图"><a href="#有权图" class="headerlink" title="有权图"></a>有权图</h3><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gez6qvfh1oj30dm0d2god.jpg" alt="image.png"></p><h2 id="连通性"><a href="#连通性" class="headerlink" title="连通性"></a>连通性</h2><h3 id="连通图"><a href="#连通图" class="headerlink" title="连通图"></a>连通图</h3><ol><li>从一个顶点到另一顶点，若存在至少一条路径，则称两个顶点是连通的。</li><li>在 <code>无向图</code> 中，若任意两个顶点都连通，则图是连通图。</li></ol><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gez6sljf43j30gc0e6wg0.jpg" alt="image.png"></p><h3 id="强连通图"><a href="#强连通图" class="headerlink" title="强连通图"></a>强连通图</h3><p>在 <code>有向图</code> 中，若任意两个顶点都含有至少一条通路，则图是强连通图。</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gez6t8h9a9j30g00eagmx.jpg" alt="image.png"></p><h3 id="连通网"><a href="#连通网" class="headerlink" title="连通网"></a>连通网</h3><p>在连通图中，若图的边具有一定的意义，每一条边都对应着一个数，称为权；权代表着连接连个顶点的代价，称这种连通图叫做连通网。</p><p><img src="https://img.kancloud.cn/21/5a/215a4cd30410052072c6174eafc60c69_498x452.png" alt="img"></p><h2 id="生成树"><a href="#生成树" class="headerlink" title="生成树"></a>生成树</h2><p>对 <code>连通图</code> 进行遍历时，遍历过程中所经过的 <code>边</code> 和 <code>顶点</code> 的组合可看做是一棵普通树，通常称为生成树。<br>如下图，a为连通图，b为生成树。</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gez6uh9jlbj310a0dagpo.jpg" alt="image.png"></p><p>因为连通图中有多个边，所以一个连通图可能会有多个生成树。</p><br><h2 id="图的存储与操作"><a href="#图的存储与操作" class="headerlink" title="图的存储与操作"></a>图的存储与操作</h2><blockquote><p>引用：<a href="https://blog.csdn.net/zjw_python/article/details/85158998" target="_blank" rel="noopener">https://blog.csdn.net/zjw_python/article/details/85158998</a></p></blockquote><h3 id="图的存储"><a href="#图的存储" class="headerlink" title="图的存储"></a>图的存储</h3><p>存储分为以下方法：</p><ul><li>邻接矩阵</li><li>邻接表</li><li>十字链表</li><li>邻接多重表</li></ul><h4 id="邻接矩阵"><a href="#邻接矩阵" class="headerlink" title="邻接矩阵"></a>邻接矩阵</h4><p>用 <code>二维数组</code> 的方式来存储图结构。</p><ul><li>无向图</li></ul><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gez6xlhwfij30do0jy401.jpg" alt="image.png"></p><p>缺点：</p><ol><li>太浪费空间</li><li>图中的顶点经常是动态的，需要添加和删除，二维数组尺寸是固定的不方便</li></ol><ul><li>有向图</li></ul><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gez6yq2c3oj30d40jygnc.jpg" alt="image.png"></p><ul><li>有向带权图</li></ul><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gez6zzespwj30ym0bq416.jpg" alt="image.png"></p><h4 id="邻接表"><a href="#邻接表" class="headerlink" title="邻接表"></a>邻接表</h4><p>链式存储。<br>图的每一个顶点都是一个头节点，其后连接着该顶点能够直接达到的相邻顶点。</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gez73265mij30n4096q6u.jpg" alt="image.png"></p><h5 id="代码实现-3"><a href="#代码实现-3" class="headerlink" title="代码实现"></a>代码实现</h5><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 邻接表</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Graph</span> </span>&#123;</span><br><span class="line">    <span class="keyword">constructor</span>() &#123;</span><br><span class="line">        <span class="comment">// 顶点数组</span></span><br><span class="line">        <span class="keyword">this</span>.vertex = []</span><br><span class="line">        <span class="comment">// 保存边（ES6中新出的 Map （映射）类型，保存键值对</span></span><br><span class="line">        <span class="comment">//      Map 比对象的好处是，键可以是任何类型，</span></span><br><span class="line">        <span class="comment">//      而对象的键只能是字符串）</span></span><br><span class="line">        <span class="keyword">this</span>.edge = <span class="keyword">new</span> <span class="built_in">Map</span>()</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 添加顶点</span></span><br><span class="line">    addVertex(data) &#123;</span><br><span class="line">        <span class="comment">// 如果目前图中还没有这个顶点时就添加</span></span><br><span class="line">        <span class="keyword">if</span> (!<span class="keyword">this</span>.vertex.includes(data)) &#123;</span><br><span class="line">            <span class="comment">// 添加新顶点</span></span><br><span class="line">            <span class="keyword">this</span>.vertex.push(data)</span><br><span class="line">            <span class="comment">// 添加对应的边</span></span><br><span class="line">            <span class="keyword">this</span>.edge.set(data, [])</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 添加边 start： 起点 end：终点</span></span><br><span class="line">    addEdge(start, end) &#123;</span><br><span class="line">        <span class="comment">// 起点作为键取出对应的边的数组</span></span><br><span class="line">        <span class="keyword">let</span> edge = <span class="keyword">this</span>.edge.get(start)</span><br><span class="line">        <span class="comment">// 如果没有边就添加</span></span><br><span class="line">        <span class="keyword">if</span> (!edge.includes(end)) &#123;</span><br><span class="line">            <span class="comment">// 把边加进去</span></span><br><span class="line">            edge.push(end)</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> g = <span class="keyword">new</span> Graph()</span><br><span class="line"><span class="comment">// 添加几个顶点</span></span><br><span class="line">g.addVertex(<span class="number">0</span>)</span><br><span class="line">g.addVertex(<span class="number">1</span>)</span><br><span class="line">g.addVertex(<span class="number">2</span>)</span><br><span class="line">g.addVertex(<span class="number">3</span>)</span><br><span class="line"><span class="comment">// 添加边</span></span><br><span class="line">g.addEdge(<span class="number">0</span>,<span class="number">1</span>)</span><br><span class="line">g.addEdge(<span class="number">0</span>,<span class="number">2</span>)</span><br><span class="line">g.addEdge(<span class="number">3</span>,<span class="number">1</span>)</span><br><span class="line">g.addEdge(<span class="number">2</span>,<span class="number">3</span>)</span><br><span class="line">g.addEdge(<span class="number">3</span>,<span class="number">2</span>)</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(g);</span><br></pre></td></tr></table></figure><h4 id="邻接多重表"><a href="#邻接多重表" class="headerlink" title="邻接多重表"></a>邻接多重表</h4><p>邻接多重表是 <code>无向图</code> 的一种存储方式。</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gez74qdks6j314m0f8gpr.jpg" alt="image.png"></p><h4 id="逆邻接表"><a href="#逆邻接表" class="headerlink" title="逆邻接表"></a>逆邻接表</h4><p>每一个顶点作为链表的头节点，后继节点所存储的是 <code>能够直接达到该顶点</code> 的相邻顶点。</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gez7bllf7gj316u0gk7g1.jpg" alt="image.png"></p><h4 id="十字链表"><a href="#十字链表" class="headerlink" title="十字链表"></a>十字链表</h4><p>每一个顶点作为链表的头节点，都可以有两个链：</p><ol><li>所有这个节点可以到达的节点</li><li>所有可以到达该节点的节点</li></ol><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gez7c55yorj318e138no0.jpg" alt="image.png"></p><br><h2 id="图的遍历"><a href="#图的遍历" class="headerlink" title="图的遍历"></a>图的遍历</h2><h3 id="介绍-10"><a href="#介绍-10" class="headerlink" title="介绍"></a>介绍</h3><p>图的遍历：依次把图中所有的顶点都访问一次。</p><p>图有两种遍历方式：</p><ul><li>深度优先遍历（DFS：Deep Frist Search）</li><li>广度优先遍历（BFS：Breath First Search）</li></ul><p>在接下来要实现的算法中，我们按照如下的约定对图中的顶点进行遍历，每个顶点最多访问两次：</p><ul><li>白色：表示该顶点未被访问。</li><li>灰色：表示该顶点被访问过，但未被探索。</li><li>黑色：表示该顶点被访问并且被探索过。</li></ul><h3 id="广度优先遍历（BFS）"><a href="#广度优先遍历（BFS）" class="headerlink" title="广度优先遍历（BFS）"></a>广度优先遍历（BFS）</h3><p>先访问一个顶点所有相邻的顶点，然后再依次访问每个顶点的相邻的顶点，以此类推，最终访问到所有的顶点。</p><p>比如，从 0 开始先访问周围顶点：</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gf0e12p2rcj30e60cqdjo.jpg" alt="image.png"></p><p>再到隔一层的点：</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gf0e1easukj30eu0d4td1.jpg" alt="image.png"></p><p>然后再隔一层：</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gf0e1of750j30ei0cmq76.jpg" alt="image.png"></p><h4 id="代码实现-4"><a href="#代码实现-4" class="headerlink" title="代码实现"></a>代码实现</h4><p>使用 <code>队列</code> 不断重放：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> Colors = &#123;</span><br><span class="line">    WHITE: <span class="number">0</span>,</span><br><span class="line">    GREY: <span class="number">1</span>,</span><br><span class="line">    BLACK: <span class="number">2</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> initializeColor = <span class="function"><span class="params">vertices</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">let</span> color = &#123;&#125;;</span><br><span class="line">    vertices.forEach(<span class="function"><span class="params">v</span> =&gt;</span> color[v] = Colors.WHITE);</span><br><span class="line">    <span class="keyword">return</span> color;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> breadthFirstSearch = <span class="function">(<span class="params">graph, startVertex, callback</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">let</span> vertices = graph.getVertices();</span><br><span class="line">    <span class="keyword">let</span> adjList = graph.getAdjList();</span><br><span class="line">    <span class="keyword">let</span> color = initializeColor(vertices);</span><br><span class="line">    <span class="keyword">let</span> queue = <span class="keyword">new</span> Queue();</span><br><span class="line"></span><br><span class="line">    queue.enqueue(startVertex);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">while</span> (!queue.isEmpty()) &#123;</span><br><span class="line">        <span class="keyword">let</span> u = queue.dequeue();</span><br><span class="line">        adjList.get(u).forEach(<span class="function"><span class="params">n</span> =&gt;</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (color[n] === Colors.WHITE) &#123;</span><br><span class="line">                color[n] = Colors.GREY;</span><br><span class="line">                queue.enqueue(n);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        color[u] = Colors.BLACK;</span><br><span class="line">        <span class="keyword">if</span> (callback) callback(u);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h3 id="深度优先遍历（DFS）"><a href="#深度优先遍历（DFS）" class="headerlink" title="深度优先遍历（DFS）"></a>深度优先遍历（DFS）</h3><p>我们选择一条支路，尽可能不断地深入，如果遇到死路就往回退，回退过程中如果遇到没探索过的支路，就进入该支路继续深入。<br>比如，我们从 0 开始</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gf0e35ksumj30e80bw422.jpg" alt="image.png"></p><p>先找一条路 <code>走到底</code>：</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gf0e3d94gkj30dg0bgn0q.jpg" alt="image.png"></p><p>到底后，回退一级再走到底：</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gf0e3m3o9oj30eo0ck0wp.jpg" alt="image.png"></p><p>以此类推。</p><h4 id="代码实现-5"><a href="#代码实现-5" class="headerlink" title="代码实现"></a>代码实现</h4><p>实现原理：使用 <code>栈</code> 不断 <code>回朔</code></p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gf0e49ool2j30kc10o4as.jpg" alt="image.png"></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> depthFirstSearchVisit = <span class="function">(<span class="params">u, color, adjList, callback</span>) =&gt;</span> &#123;</span><br><span class="line">    color[u] = Colors.GREY;</span><br><span class="line">    <span class="keyword">if</span> (callback) callback(u);</span><br><span class="line"></span><br><span class="line">    adjList.get(u).forEach(<span class="function"><span class="params">n</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (color[n] === Colors.WHITE) &#123;</span><br><span class="line">            depthFirstSearchVisit(n, color, adjList, callback);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    color[u] = Colors.BLACK;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> depthFirstSearch = <span class="function">(<span class="params">graph, callback</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">let</span> vertices = graph.getVertices();</span><br><span class="line">    <span class="keyword">let</span> adjList = graph.getAdjList();</span><br><span class="line">    <span class="keyword">let</span> color = initializeColor(vertices);</span><br><span class="line"></span><br><span class="line">    vertices.forEach(<span class="function"><span class="params">v</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (color[v] === Colors.WHITE) &#123;</span><br><span class="line">            depthFirstSearchVisit(v, color, adjList, callback);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;);</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><br><h2 id="最短路径"><a href="#最短路径" class="headerlink" title="最短路径"></a>最短路径</h2><p>图中两个顶点之间最短的路径。</p><h3 id="无向图"><a href="#无向图" class="headerlink" title="无向图"></a>无向图</h3><p>对于 <code>无向图</code> 来说，可以使用 <code>BFS</code> 算法来找到两点间的路径。</p><h3 id="有向图"><a href="#有向图" class="headerlink" title="有向图"></a>有向图</h3><ul><li>Dijkstra （迪杰斯特拉）算法</li><li>Floyd（弗洛伊德）算法</li></ul><br><h2 id="拓扑排序"><a href="#拓扑排序" class="headerlink" title="拓扑排序"></a>拓扑排序</h2><p>在图论中，拓扑排序（Topological Sorting）是一个有向无环图（DAG, Directed Acyclic Graph）的所有 <code>顶点的线性序列</code>。</p><p>且该序列必须满足下面两个条件：</p><ol><li>每个顶点出现且只出现一次。</li><li>若存在一条从顶点 A 到顶点 B 的路径，那么在序列中顶点 A 出现在顶点 B 的前面。</li></ol><h3 id="有向无环图"><a href="#有向无环图" class="headerlink" title="有向无环图"></a>有向无环图</h3><p>无环：由任意一点出点，无法回到这个点。</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gf0e66cjywj30my0eith3.jpg" alt="image.png"></p><h3 id="拓扑排序用途"><a href="#拓扑排序用途" class="headerlink" title="拓扑排序用途"></a>拓扑排序用途</h3><p>拓扑排序通常用来把图 “排序” 成具有依赖关系的一个线性序列。</p><h3 id="实现思路"><a href="#实现思路" class="headerlink" title="实现思路"></a>实现思路</h3><p>实现流程：</p><ol><li>从 DAG 图中选择一个没有前驱（即入度为0）的顶点并输出。</li><li>从图中删除该顶点和所有以它为起点的有向边。</li><li>重复 1 和 2 直到当前的 DAG 图为空或当前图中不存在无前驱的顶点为止。后一种情况说明有向图中必然存在环。</li></ol><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gf0e73amalj30vu0jejxl.jpg" alt="image.png"></p><p>所以输出序列为：1,2,4,3,5</p><p>代码：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 拓扑排序序列</span></span><br><span class="line">    topolocalSort() &#123;</span><br><span class="line">        <span class="keyword">let</span> ret = [] <span class="comment">// 结果</span></span><br><span class="line">        <span class="comment">// 直到没有顶点结束</span></span><br><span class="line">        <span class="keyword">while</span> (<span class="keyword">this</span>.vertexes.length &gt; <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="comment">// 找出入读为 0 的顶点</span></span><br><span class="line">            <span class="keyword">this</span>.vertexes.forEach(<span class="function">(<span class="params">v, k</span>) =&gt;</span> &#123;</span><br><span class="line">                <span class="comment">// 入度为 0 </span></span><br><span class="line">                <span class="keyword">if</span> (v.in == <span class="number">0</span>) &#123;</span><br><span class="line">                    ret.push(v.data)</span><br><span class="line">                    <span class="comment">// 把边终点的入度都减一</span></span><br><span class="line">                    <span class="keyword">this</span>.edge.get(v).forEach(<span class="function"><span class="params">w</span> =&gt;</span> &#123;</span><br><span class="line">                        w.in--</span><br><span class="line">                    &#125;)</span><br><span class="line">                    <span class="comment">// 删除这个顶点发出的所有的边</span></span><br><span class="line">                    <span class="keyword">this</span>.edge.delete(v)</span><br><span class="line">                    <span class="comment">// 从顶点数组中删除这个顶点</span></span><br><span class="line">                    <span class="keyword">this</span>.vertexes.splice(k, <span class="number">1</span>)</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;)</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 返回结束</span></span><br><span class="line">        <span class="keyword">return</span> ret</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure><br><h2 id="代码实现-6"><a href="#代码实现-6" class="headerlink" title="代码实现"></a>代码实现</h2><h3 id="创建类"><a href="#创建类" class="headerlink" title="创建类"></a>创建类</h3><p>这里使用了 ES6 中的 <code>面向对象</code> 的语法。<br>先实现类及添加顶点的功能。</p><h4 id="添加顶点"><a href="#添加顶点" class="headerlink" title="添加顶点"></a>添加顶点</h4><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gf0ekzk5f5j30lo13m16i.jpg" alt="image.png"></p><p>上面的代码实现了向图中添加一些顶点，但现在顶点还没有边。<br>接下来添加边：</p><h4 id="添加边"><a href="#添加边" class="headerlink" title="添加边"></a>添加边</h4><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gf0elohg2oj30ia0c8jx3.jpg" alt="image.png"></p><p>测试：</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gf0em51d7wj318q0u47p4.jpg" alt="image.png"></p><p>以上代码</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 顶点类 </span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Vertex</span> </span>&#123;</span><br><span class="line">    <span class="keyword">constructor</span>(data) &#123;</span><br><span class="line">        <span class="comment">// 数据</span></span><br><span class="line">        <span class="keyword">this</span>.data = data</span><br><span class="line">        <span class="comment">// 入度</span></span><br><span class="line">        <span class="keyword">this</span>.in = <span class="number">0</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 图类</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Graph</span> </span>&#123;</span><br><span class="line">    <span class="keyword">constructor</span>() &#123;</span><br><span class="line">        <span class="comment">// 顶点数组</span></span><br><span class="line">        <span class="keyword">this</span>.vertexes = []</span><br><span class="line">        <span class="comment">// 边</span></span><br><span class="line">        <span class="keyword">this</span>.edge = <span class="keyword">new</span> <span class="built_in">Map</span>()</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 添加点</span></span><br><span class="line">    addVertex(data) &#123;</span><br><span class="line">        <span class="comment">// 创建点节点</span></span><br><span class="line">        <span class="keyword">let</span> newVertex = <span class="keyword">new</span> Vertex(data)</span><br><span class="line">        <span class="comment">// 如果图中还没有这个顶点就添加</span></span><br><span class="line">        <span class="keyword">if</span> (<span class="number">-1</span> === <span class="keyword">this</span>.vertexes.findIndex(<span class="function"><span class="params">v</span> =&gt;</span> v.data == data)) &#123;</span><br><span class="line">            <span class="keyword">this</span>.vertexes.push(newVertex)</span><br><span class="line">            <span class="comment">// 初始化边的数据</span></span><br><span class="line">            <span class="keyword">this</span>.edge.set(newVertex, [])</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 添加边</span></span><br><span class="line">    <span class="comment">// from: 起点</span></span><br><span class="line">    <span class="comment">// to ： 终点</span></span><br><span class="line">    addEdge(<span class="keyword">from</span>,to) &#123;</span><br><span class="line">        <span class="comment">// 先根据值找出两个顶点对象</span></span><br><span class="line">        <span class="keyword">let</span> fromVertex = <span class="keyword">this</span>.vertexes.find(<span class="function"><span class="params">v</span>=&gt;</span>v.data==<span class="keyword">from</span>)</span><br><span class="line">        <span class="keyword">let</span> toVertex = <span class="keyword">this</span>.vertexes.find(<span class="function"><span class="params">v</span>=&gt;</span>v.data==to)</span><br><span class="line">        <span class="comment">// 如果有两个顶点</span></span><br><span class="line">        <span class="keyword">if</span> (fromVertex &amp;&amp; toVertex) &#123;</span><br><span class="line">            <span class="comment">// 把终点的入度 +1</span></span><br><span class="line">            toVertex.in++</span><br><span class="line">            <span class="comment">// 向起点对应的边的数组中添加一个点</span></span><br><span class="line">            <span class="keyword">this</span>.edge.get(fromVertex).push(toVertex)</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> g = <span class="keyword">new</span> Graph()</span><br><span class="line">g.addVertex(<span class="string">'a'</span>)</span><br><span class="line">g.addVertex(<span class="string">'b'</span>)</span><br><span class="line">g.addVertex(<span class="string">'c'</span>)</span><br><span class="line">g.addVertex(<span class="string">'d'</span>)</span><br><span class="line">g.addVertex(<span class="string">'e'</span>)</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(g.vertexes);</span><br><span class="line"><span class="built_in">console</span>.log(g.edge);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 添加边</span></span><br><span class="line">g.addEdge(<span class="string">'a'</span>,<span class="string">'d'</span>)</span><br><span class="line">g.addEdge(<span class="string">'d'</span>,<span class="string">'e'</span>)</span><br><span class="line">g.addEdge(<span class="string">'e'</span>,<span class="string">'c'</span>)</span><br><span class="line">g.addEdge(<span class="string">'c'</span>,<span class="string">'a'</span>)</span><br><span class="line">g.addEdge(<span class="string">'b'</span>,<span class="string">'a'</span>)</span><br><span class="line"><span class="built_in">console</span>.log(g.vertexes);</span><br><span class="line"><span class="built_in">console</span>.log(g.edge);</span><br></pre></td></tr></table></figure><h4 id="广度优先遍历（BFS）-1"><a href="#广度优先遍历（BFS）-1" class="headerlink" title="广度优先遍历（BFS）"></a>广度优先遍历（BFS）</h4><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gf0enomz0ej30kk0tcwse.jpg" alt="image.png"></p><p>测试：</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gf0eo5byoxj31ko0v84qp.jpg" alt="image.png"></p><p>结果：</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gf0eom4xuej3086072jtf.jpg" alt="image.png"></p><h4 id="深度优先遍历（DFS）-1"><a href="#深度优先遍历（DFS）-1" class="headerlink" title="深度优先遍历（DFS）"></a>深度优先遍历（DFS）</h4><p>可以使用 <code>栈</code> 或者 <code>递归</code> 还实现，以下是实现递归的实现方法：</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gf0ep0laf0j30pm0zs1at.jpg" alt="image.png"></p><p>结果：</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gf0epqmd3dj31hy0o6b29.jpg" alt="image.png"></p><h4 id="两个顶点之间的路径"><a href="#两个顶点之间的路径" class="headerlink" title="两个顶点之间的路径"></a>两个顶点之间的路径</h4><h5 id="在-BFS-时记录来路"><a href="#在-BFS-时记录来路" class="headerlink" title="在 BFS 时记录来路"></a>在 BFS 时记录来路</h5><p>修改 <code>BFS</code> 的代码，在遍历时，把每个顶点的上一个顶点（来路）记录下来：</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gf0eqh4g4qj30so0zuh5t.jpg" alt="image.png"></p><p>结果：</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gf0eqx7h6uj31pm0n4hdt.jpg" alt="image.png"></p><h5 id="反向找两个顶点之间的路径"><a href="#反向找两个顶点之间的路径" class="headerlink" title="反向找两个顶点之间的路径"></a>反向找两个顶点之间的路径</h5><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gf0erk39f1j30om0p8ao9.jpg" alt="image.png"></p><p>结果：</p><p><img src="http://ww1.sinaimg.cn/large/007WurYGgy1gf0erzahdvj31ku0m41kx.jpg" alt="image.png"></p><p>总的代码：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 顶点类 </span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Vertex</span> </span>&#123;</span><br><span class="line">    <span class="keyword">constructor</span>(data) &#123;</span><br><span class="line">        <span class="comment">// 数据</span></span><br><span class="line">        <span class="keyword">this</span>.data = data</span><br><span class="line">        <span class="comment">// 入度</span></span><br><span class="line">        <span class="keyword">this</span>.in = <span class="number">0</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 图类</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Graph</span> </span>&#123;</span><br><span class="line">    <span class="keyword">constructor</span>() &#123;</span><br><span class="line">        <span class="comment">// 顶点数组</span></span><br><span class="line">        <span class="keyword">this</span>.vertexes = []</span><br><span class="line">        <span class="comment">// 边</span></span><br><span class="line">        <span class="keyword">this</span>.edge = <span class="keyword">new</span> <span class="built_in">Map</span>()</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 添加点</span></span><br><span class="line">    addVertex(data) &#123;</span><br><span class="line">        <span class="comment">// 创建点节点</span></span><br><span class="line">        <span class="keyword">let</span> newVertex = <span class="keyword">new</span> Vertex(data)</span><br><span class="line">        <span class="comment">// 如果图中还没有这个顶点就添加</span></span><br><span class="line">        <span class="keyword">if</span> (<span class="number">-1</span> === <span class="keyword">this</span>.vertexes.findIndex(<span class="function"><span class="params">v</span> =&gt;</span> v.data == data)) &#123;</span><br><span class="line">            <span class="keyword">this</span>.vertexes.push(newVertex)</span><br><span class="line">            <span class="comment">// 初始化边的数据</span></span><br><span class="line">            <span class="keyword">this</span>.edge.set(newVertex, [])</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 添加边</span></span><br><span class="line">    <span class="comment">// from: 起点</span></span><br><span class="line">    <span class="comment">// to ： 终点</span></span><br><span class="line">    addEdge(<span class="keyword">from</span>, to) &#123;</span><br><span class="line">        <span class="comment">// 先根据值找出两个顶点对象</span></span><br><span class="line">        <span class="keyword">let</span> fromVertex = <span class="keyword">this</span>.vertexes.find(<span class="function"><span class="params">v</span> =&gt;</span> v.data == <span class="keyword">from</span>)</span><br><span class="line">        <span class="keyword">let</span> toVertex = <span class="keyword">this</span>.vertexes.find(<span class="function"><span class="params">v</span> =&gt;</span> v.data == to)</span><br><span class="line">        <span class="comment">// 如果有两个顶点</span></span><br><span class="line">        <span class="keyword">if</span> (fromVertex &amp;&amp; toVertex) &#123;</span><br><span class="line">            <span class="comment">// 把终点的入度 +1</span></span><br><span class="line">            toVertex.in++</span><br><span class="line">            <span class="comment">// 向起点对应的边的数组中添加一个点</span></span><br><span class="line">            <span class="keyword">this</span>.edge.get(fromVertex).push(toVertex)</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 广度优先遍历 （BFS）</span></span><br><span class="line">    <span class="comment">// start ： 起点</span></span><br><span class="line">    bfs(start) &#123;</span><br><span class="line">        <span class="comment">// 先找出起点节点</span></span><br><span class="line">        <span class="keyword">let</span> startVertex = <span class="keyword">this</span>.vertexes.find(<span class="function"><span class="params">v</span> =&gt;</span> v.data == start)</span><br><span class="line">        <span class="keyword">let</span> ret = [startVertex] <span class="comment">// 遍历完之后的结果</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">// 记录每个顶点上一个顶点</span></span><br><span class="line">        <span class="keyword">let</span> lastVertex = <span class="keyword">new</span> <span class="built_in">Map</span>()</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 1. 初始化一个代表是否已经访问过的 Map</span></span><br><span class="line">        <span class="comment">// 定义 Map 保存所有顶点的访问状态</span></span><br><span class="line">        <span class="keyword">let</span> visited = <span class="keyword">new</span> <span class="built_in">Map</span>()</span><br><span class="line">        <span class="comment">// 初始化所有的顶点做开始时都没有被访问过</span></span><br><span class="line">        <span class="keyword">this</span>.vertexes.forEach(<span class="function"><span class="params">v</span> =&gt;</span> &#123;</span><br><span class="line">            visited.set(v, <span class="literal">false</span>)</span><br><span class="line">        &#125;)</span><br><span class="line">        <span class="comment">// 2. 开始</span></span><br><span class="line">        <span class="keyword">let</span> queue = []</span><br><span class="line">        <span class="comment">// 先把起点放到队列中并标识为已经访问过</span></span><br><span class="line">        queue.push(startVertex)</span><br><span class="line">        visited.set(startVertex, <span class="literal">true</span>)</span><br><span class="line">        <span class="comment">// 循环队列中所有的顶点</span></span><br><span class="line">        <span class="keyword">while</span> (queue.length &gt; <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="comment">// 取出队列中第1个顶点</span></span><br><span class="line">            <span class="keyword">let</span> first = queue.shift()</span><br><span class="line">            <span class="comment">// 依次访问所有的顶点</span></span><br><span class="line">            <span class="keyword">this</span>.edge.get(first).forEach(<span class="function"><span class="params">v</span> =&gt;</span> &#123;</span><br><span class="line">                <span class="comment">// 如果还没有被访问过就放到队列</span></span><br><span class="line">                <span class="keyword">if</span> (!visited.get(v)) &#123;</span><br><span class="line">                    queue.push(v)</span><br><span class="line">                    ret.push(v)</span><br><span class="line">                    <span class="comment">// 标记这个点已经被访问过了</span></span><br><span class="line">                    visited.set(v, <span class="literal">true</span>)</span><br><span class="line">                    <span class="comment">// 记录一下，这个顶点的上一个顶点（来路）</span></span><br><span class="line">                    lastVertex.set(v, first)</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;)</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// console.log(lastVertex);</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">// 返回遍历的结果</span></span><br><span class="line">        <span class="keyword">return</span> &#123;</span><br><span class="line">            result: ret, <span class="comment">// 遍历的点</span></span><br><span class="line">            fromWhere: lastVertex   <span class="comment">// 来路 Map</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 深度优先遍历</span></span><br><span class="line">    dfs(start) &#123;</span><br><span class="line">        <span class="comment">// 先找出起点节点</span></span><br><span class="line">        <span class="keyword">let</span> startVertex = <span class="keyword">this</span>.vertexes.find(<span class="function"><span class="params">v</span> =&gt;</span> v.data == start)</span><br><span class="line">        <span class="keyword">let</span> ret = [startVertex]  <span class="comment">// 遍历完之后的结果</span></span><br><span class="line">        <span class="comment">// 1. 初始化一个代表是否已经访问过的 Map</span></span><br><span class="line">        <span class="comment">// 定义 Map 保存所有顶点的访问状态</span></span><br><span class="line">        <span class="keyword">let</span> visited = <span class="keyword">new</span> <span class="built_in">Map</span>()</span><br><span class="line">        <span class="comment">// 初始化所有的顶点最开始时都没有被访问过</span></span><br><span class="line">        <span class="keyword">this</span>.vertexes.forEach(<span class="function"><span class="params">v</span> =&gt;</span> &#123;</span><br><span class="line">            visited.set(v, <span class="literal">false</span>)</span><br><span class="line">        &#125;)</span><br><span class="line">        <span class="comment">// 直接标记起点已经被访问过了</span></span><br><span class="line">        visited.set(startVertex, <span class="literal">true</span>)</span><br><span class="line">        <span class="comment">// 递归访问</span></span><br><span class="line">        <span class="keyword">this</span>._dfs(startVertex, visited, ret)</span><br><span class="line">        <span class="keyword">return</span> ret</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// v: 起点</span></span><br><span class="line">    <span class="comment">// visited： 顶点是否已经访问过的状态</span></span><br><span class="line">    _dfs(v, visited, ret) &#123;</span><br><span class="line">        <span class="comment">// 取出所有下一个顶点</span></span><br><span class="line">        <span class="keyword">this</span>.edge.get(v).forEach(<span class="function"><span class="params">w</span> =&gt;</span> &#123;</span><br><span class="line">            <span class="comment">// 如果这个点还没有被访问过，就递归访问这个点</span></span><br><span class="line">            <span class="keyword">if</span> (!visited.get(w)) &#123;</span><br><span class="line">                <span class="comment">// 记录一下经过了这个点</span></span><br><span class="line">                ret.push(w)</span><br><span class="line">                <span class="comment">// 标记为这个点已经被访问过了</span></span><br><span class="line">                visited.set(w, <span class="literal">true</span>)</span><br><span class="line">                <span class="comment">// 递归遍历这个点</span></span><br><span class="line">                <span class="keyword">this</span>._dfs(w, visited, ret)</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 找出两个顶点之间的路径</span></span><br><span class="line">    <span class="comment">// from： 起点   to： 终点</span></span><br><span class="line">    path(<span class="keyword">from</span>, to) &#123;</span><br><span class="line">        <span class="comment">// 1. 先从起点开始 BFS 并得到来路 Map</span></span><br><span class="line">        <span class="keyword">let</span> &#123; fromWhere &#125; = <span class="keyword">this</span>.bfs(<span class="keyword">from</span>)</span><br><span class="line">        <span class="comment">// 2. 以 to 为起点，反向查找可以到达 to 这个顶点的路径</span></span><br><span class="line">        <span class="comment">// 从顶点数组中找出这个值对应的顶点</span></span><br><span class="line">        to = <span class="keyword">this</span>.vertexes.find(<span class="function"><span class="params">v</span> =&gt;</span> v.data = to)</span><br><span class="line">        <span class="comment">// 先把这个终点作为起点</span></span><br><span class="line">        <span class="keyword">let</span> start = to</span><br><span class="line">        <span class="keyword">let</span> ret = [] <span class="comment">// 路径结果</span></span><br><span class="line">        <span class="comment">// 从终点一直向前找，直到上一个顶点等于起点</span></span><br><span class="line">        <span class="keyword">while</span> (<span class="keyword">from</span> != start.data) &#123;</span><br><span class="line">            <span class="comment">// 找出当前节点的上一个顶点</span></span><br><span class="line">            start = fromWhere.get(start)</span><br><span class="line">            <span class="comment">// 从数组前面添加</span></span><br><span class="line">            ret.unshift(start)</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 终点加到路径的最后</span></span><br><span class="line">        ret.push(to)</span><br><span class="line">        <span class="keyword">return</span> ret</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 拓扑排序序列</span></span><br><span class="line">    topolocalSort() &#123;</span><br><span class="line">        <span class="keyword">let</span> ret = [] <span class="comment">// 结果</span></span><br><span class="line">        <span class="comment">// 直到没有顶点结束</span></span><br><span class="line">        <span class="keyword">while</span> (<span class="keyword">this</span>.vertexes.length &gt; <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="comment">// 找出入读为 0 的顶点</span></span><br><span class="line">            <span class="keyword">this</span>.vertexes.forEach(<span class="function">(<span class="params">v, k</span>) =&gt;</span> &#123;</span><br><span class="line">                <span class="comment">// 入度为 0 </span></span><br><span class="line">                <span class="keyword">if</span> (v.in == <span class="number">0</span>) &#123;</span><br><span class="line">                    ret.push(v.data)</span><br><span class="line">                    <span class="comment">// 把边终点的入度都减一</span></span><br><span class="line">                    <span class="keyword">this</span>.edge.get(v).forEach(<span class="function"><span class="params">w</span> =&gt;</span> &#123;</span><br><span class="line">                        w.in--</span><br><span class="line">                    &#125;)</span><br><span class="line">                    <span class="comment">// 删除这个顶点发出的所有的边</span></span><br><span class="line">                    <span class="keyword">this</span>.edge.delete(v)</span><br><span class="line">                    <span class="comment">// 从顶点数组中删除这个顶点</span></span><br><span class="line">                    <span class="keyword">this</span>.vertexes.splice(k, <span class="number">1</span>)</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;)</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 返回结束</span></span><br><span class="line">        <span class="keyword">return</span> ret</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> g = <span class="keyword">new</span> Graph()</span><br><span class="line"><span class="comment">// g.addVertex('a')</span></span><br><span class="line"><span class="comment">// g.addVertex('b')</span></span><br><span class="line"><span class="comment">// g.addVertex('c')</span></span><br><span class="line"><span class="comment">// g.addVertex('d')</span></span><br><span class="line"><span class="comment">// g.addVertex('e')</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// console.log(g.vertexes);</span></span><br><span class="line"><span class="comment">// console.log(g.edge);</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// // 添加边</span></span><br><span class="line"><span class="comment">// g.addEdge('a', 'd')</span></span><br><span class="line"><span class="comment">// g.addEdge('d', 'e')</span></span><br><span class="line"><span class="comment">// g.addEdge('e', 'c')</span></span><br><span class="line"><span class="comment">// g.addEdge('c', 'a')</span></span><br><span class="line"><span class="comment">// g.addEdge('b', 'a')</span></span><br><span class="line"><span class="comment">// console.log(g.vertexes);</span></span><br><span class="line"><span class="comment">// console.log(g.edge);</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// g.addVertex(0)</span></span><br><span class="line"><span class="comment">// g.addVertex(1)</span></span><br><span class="line"><span class="comment">// g.addVertex(2)</span></span><br><span class="line"><span class="comment">// g.addVertex(3)</span></span><br><span class="line"><span class="comment">// g.addVertex(4)</span></span><br><span class="line"><span class="comment">// g.addVertex(5)</span></span><br><span class="line"><span class="comment">// g.addVertex(6)</span></span><br><span class="line"><span class="comment">// g.addVertex(7)</span></span><br><span class="line"><span class="comment">// g.addVertex(8)</span></span><br><span class="line"><span class="comment">// g.addVertex(9)</span></span><br><span class="line"><span class="comment">// g.addVertex(10)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// g.addEdge(0, 1)</span></span><br><span class="line"><span class="comment">// g.addEdge(0, 2)</span></span><br><span class="line"><span class="comment">// g.addEdge(0, 3)</span></span><br><span class="line"><span class="comment">// g.addEdge(0, 4)</span></span><br><span class="line"><span class="comment">// g.addEdge(1, 0)</span></span><br><span class="line"><span class="comment">// g.addEdge(1, 4)</span></span><br><span class="line"><span class="comment">// g.addEdge(1, 7)</span></span><br><span class="line"><span class="comment">// g.addEdge(1, 9)</span></span><br><span class="line"><span class="comment">// g.addEdge(2, 0)</span></span><br><span class="line"><span class="comment">// g.addEdge(3, 0)</span></span><br><span class="line"><span class="comment">// g.addEdge(3, 5)</span></span><br><span class="line"><span class="comment">// g.addEdge(3, 6)</span></span><br><span class="line"><span class="comment">// g.addEdge(4, 0)</span></span><br><span class="line"><span class="comment">// g.addEdge(4, 1)</span></span><br><span class="line"><span class="comment">// g.addEdge(4, 5)</span></span><br><span class="line"><span class="comment">// g.addEdge(5, 3)</span></span><br><span class="line"><span class="comment">// g.addEdge(5, 4)</span></span><br><span class="line"><span class="comment">// g.addEdge(6, 3)</span></span><br><span class="line"><span class="comment">// g.addEdge(7, 1)</span></span><br><span class="line"><span class="comment">// g.addEdge(7, 8)</span></span><br><span class="line"><span class="comment">// g.addEdge(7, 10)</span></span><br><span class="line"><span class="comment">// g.addEdge(8, 7)</span></span><br><span class="line"><span class="comment">// g.addEdge(9, 1)</span></span><br><span class="line"><span class="comment">// g.addEdge(10, 7)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// let ret = g.bfs(0)</span></span><br><span class="line"><span class="comment">// console.log(ret);</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// console.log(g.path(9, 4));</span></span><br><span class="line"></span><br><span class="line">g.addVertex(<span class="number">1</span>)</span><br><span class="line">g.addVertex(<span class="number">2</span>)</span><br><span class="line">g.addVertex(<span class="number">3</span>)</span><br><span class="line">g.addVertex(<span class="number">4</span>)</span><br><span class="line">g.addVertex(<span class="number">5</span>)</span><br><span class="line"></span><br><span class="line">g.addEdge(<span class="number">1</span>,<span class="number">2</span>)</span><br><span class="line">g.addEdge(<span class="number">1</span>,<span class="number">4</span>)</span><br><span class="line">g.addEdge(<span class="number">2</span>,<span class="number">3</span>)</span><br><span class="line">g.addEdge(<span class="number">2</span>,<span class="number">4</span>)</span><br><span class="line">g.addEdge(<span class="number">3</span>,<span class="number">5</span>)</span><br><span class="line">g.addEdge(<span class="number">4</span>,<span class="number">3</span>)</span><br><span class="line">g.addEdge(<span class="number">4</span>,<span class="number">5</span>)</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(g.topolocalSort());</span><br></pre></td></tr></table></figure><br></div><footer class="post-footer"><div class="post-tags"><a href="/tags/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/" rel="tag"><i class="fa fa-tag"></i> 数据结构与算法</a></div><div class="post-nav"><div class="post-nav-next post-nav-item"><a href="/article/1a004747.html" rel="next" title="数据结构与算法 (js版)  -- 排序"><i class="fa fa-chevron-left"></i> 数据结构与算法 (js版) -- 排序</a></div><span class="post-nav-divider"></span><div class="post-nav-prev post-nav-item"> <a href="/article/3d977fbc.html" rel="prev" title="React Native -- 仿抖音APP开发">React Native -- 仿抖音APP开发<i class="fa fa-chevron-right"></i></a></div></div></footer></div></article><div class="post-spread"></div></div></div><div class="comments" id="comments"></div></div><div class="sidebar-toggle"><div class="sidebar-toggle-line-wrap"><span class="sidebar-toggle-line sidebar-toggle-line-first"></span><span class="sidebar-toggle-line sidebar-toggle-line-middle"></span><span class="sidebar-toggle-line sidebar-toggle-line-last"></span></div></div><aside id="sidebar" class="sidebar"><div class="sidebar-inner"><ul class="sidebar-nav motion-element"><li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap"> 文章目录</li><li class="sidebar-nav-overview" data-target="site-overview-wrap"> 站点概览</li></ul><section class="site-overview-wrap sidebar-panel"><div class="site-overview"><div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person"> <img class="site-author-image" itemprop="image" src="http://ww1.sinaimg.cn/large/007WurYGgy1ge8nxttd9nj302s02s0si.jpg" alt="King-XiYu"><p class="site-author-name" itemprop="name">King-XiYu</p><p class="site-description motion-element" itemprop="description">有志者事竟成</p></div><nav class="site-state motion-element"><div class="site-state-item site-state-posts"> <a href="/archives/"><span class="site-state-item-count">37</span> <span class="site-state-item-name">日志</span></a></div><div class="site-state-item site-state-categories"> <a href="/categories/index.html"><span class="site-state-item-count">11</span> <span class="site-state-item-name">分类</span></a></div><div class="site-state-item site-state-tags"> <a href="/tags/index.html"><span class="site-state-item-count">10</span> <span class="site-state-item-name">标签</span></a></div></nav><div class="feed-link motion-element"><a href="/atom.xml" rel="alternate"><i class="fa fa-rss"></i> RSS</a></div><div class="links-of-author motion-element"><span class="links-of-author-item"><a href="https://gitee.com/King-XiYu" target="_blank" title="Gitee"><i class="fa fa-fw fa-hand-o-right"></i> Gitee</a></span><span class="links-of-author-item"><a href="https://github.com/King-XiYu" target="_blank" title="GitHub"><i class="fa fa-fw fa-github"></i> GitHub</a></span></div><div class="links-of-blogroll motion-element links-of-blogroll-inline"><div class="links-of-blogroll-title"><i class="fa fa-fw fa-link"></i> Links</div><ul class="links-of-blogroll-list"><li class="links-of-blogroll-item"> <a href="https://www.baidu.com/" title="度娘" target="_blank">度娘</a></li><li class="links-of-blogroll-item"> <a href="https://www.google.com/" title="Google" target="_blank">Google</a></li></ul></div></div></section><section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active"><div class="post-toc"><div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#线性结构"><span class="nav-number">1.</span> <span class="nav-text">线性结构</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#数组"><span class="nav-number">1.1.</span> <span class="nav-text">数组</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#链表"><span class="nav-number">1.2.</span> <span class="nav-text">链表</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#介绍"><span class="nav-number">1.2.1.</span> <span class="nav-text">介绍</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#存储结构"><span class="nav-number">1.2.1.1.</span> <span class="nav-text">存储结构</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#特点"><span class="nav-number">1.2.1.2.</span> <span class="nav-text">特点</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#类型"><span class="nav-number">1.2.1.3.</span> <span class="nav-text">类型</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#代码实现"><span class="nav-number">1.2.2.</span> <span class="nav-text">代码实现</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#写法一、传统的写法（使用-function-定义类）"><span class="nav-number">1.2.2.1.</span> <span class="nav-text">写法一、传统的写法（使用 function 定义类）</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#写法二、ES6-中新语法-（使用-class-定义类）"><span class="nav-number">1.2.2.2.</span> <span class="nav-text">写法二、ES6 中新语法 （使用 class 定义类）</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#栈"><span class="nav-number">1.3.</span> <span class="nav-text">栈</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#介绍-1"><span class="nav-number">1.3.1.</span> <span class="nav-text">介绍</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#特点-1"><span class="nav-number">1.3.1.1.</span> <span class="nav-text">特点</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#实现方式"><span class="nav-number">1.3.2.</span> <span class="nav-text">实现方式</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#顺序栈"><span class="nav-number">1.3.2.1.</span> <span class="nav-text">顺序栈</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#链式栈"><span class="nav-number">1.3.2.2.</span> <span class="nav-text">链式栈</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#队列"><span class="nav-number">1.4.</span> <span class="nav-text">队列</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#介绍-2"><span class="nav-number">1.4.1.</span> <span class="nav-text">介绍</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#特点-2"><span class="nav-number">1.4.1.1.</span> <span class="nav-text">特点</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#实现方式-1"><span class="nav-number">1.4.1.2.</span> <span class="nav-text">实现方式</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#应用场景"><span class="nav-number">1.4.1.3.</span> <span class="nav-text">应用场景</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#散列表"><span class="nav-number">1.5.</span> <span class="nav-text">散列表</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#介绍-3"><span class="nav-number">1.5.1.</span> <span class="nav-text">介绍</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#JS-中的-对象-和-Map"><span class="nav-number">1.5.1.1.</span> <span class="nav-text">JS 中的 对象 和 Map</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#散列函数"><span class="nav-number">1.5.1.2.</span> <span class="nav-text">散列函数</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#散列冲突"><span class="nav-number">1.5.1.3.</span> <span class="nav-text">散列冲突</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#开放寻址法"><span class="nav-number">1.5.1.3.1.</span> <span class="nav-text">开放寻址法</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#链表法"><span class="nav-number">1.5.1.3.2.</span> <span class="nav-text">链表法</span></a></li></ol></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#Javascript-代码实现"><span class="nav-number">1.5.2.</span> <span class="nav-text">Javascript 代码实现</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#树"><span class="nav-number">2.</span> <span class="nav-text">树</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#树的概念"><span class="nav-number">2.1.</span> <span class="nav-text">树的概念</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#特点："><span class="nav-number">2.1.1.</span> <span class="nav-text">特点：</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#高度、深度和层"><span class="nav-number">2.1.1.1.</span> <span class="nav-text">高度、深度和层</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#度"><span class="nav-number">2.1.1.2.</span> <span class="nav-text">度</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#节点关系"><span class="nav-number">2.1.1.3.</span> <span class="nav-text">节点关系</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#一般二叉树"><span class="nav-number">2.2.</span> <span class="nav-text">一般二叉树</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#介绍-4"><span class="nav-number">2.2.1.</span> <span class="nav-text">介绍</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#特点-3"><span class="nav-number">2.2.1.1.</span> <span class="nav-text">特点</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#分类"><span class="nav-number">2.2.1.2.</span> <span class="nav-text">分类</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#满二叉树"><span class="nav-number">2.2.1.2.1.</span> <span class="nav-text">满二叉树</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#完全二叉树"><span class="nav-number">2.2.1.2.2.</span> <span class="nav-text">完全二叉树</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#平衡二叉树"><span class="nav-number">2.2.1.2.3.</span> <span class="nav-text">平衡二叉树</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#二叉搜索树（BST-Binary-Search-Tree）"><span class="nav-number">2.2.1.2.4.</span> <span class="nav-text">二叉搜索树（BST-Binary Search Tree）</span></a></li></ol></li><li class="nav-item nav-level-4"><a class="nav-link" href="#存储方式"><span class="nav-number">2.2.1.3.</span> <span class="nav-text">存储方式</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#链式存储"><span class="nav-number">2.2.1.3.1.</span> <span class="nav-text">链式存储</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#顺序存储"><span class="nav-number">2.2.1.3.2.</span> <span class="nav-text">顺序存储</span></a></li></ol></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#树和森林和二叉树的转换"><span class="nav-number">2.3.</span> <span class="nav-text">树和森林和二叉树的转换</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#森林"><span class="nav-number">2.3.1.</span> <span class="nav-text">森林</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#森林、树、二叉树之间的转换"><span class="nav-number">2.3.2.</span> <span class="nav-text">森林、树、二叉树之间的转换</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#树转二叉树"><span class="nav-number">2.3.2.1.</span> <span class="nav-text">树转二叉树</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#森林转二叉树"><span class="nav-number">2.3.2.2.</span> <span class="nav-text">森林转二叉树</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#二叉树转成树"><span class="nav-number">2.3.2.3.</span> <span class="nav-text">二叉树转成树</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#二叉树转成森林"><span class="nav-number">2.3.2.4.</span> <span class="nav-text">二叉树转成森林</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#二叉树的遍历"><span class="nav-number">2.4.</span> <span class="nav-text">二叉树的遍历</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#介绍-5"><span class="nav-number">2.4.1.</span> <span class="nav-text">介绍</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#遍历方法"><span class="nav-number">2.4.2.</span> <span class="nav-text">遍历方法</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#遍历代码实现"><span class="nav-number">2.4.3.</span> <span class="nav-text">遍历代码实现</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#前、中、后序遍历"><span class="nav-number">2.4.3.1.</span> <span class="nav-text">前、中、后序遍历</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#层序遍历代码实现"><span class="nav-number">2.4.4.</span> <span class="nav-text">层序遍历代码实现</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#搜索二叉树"><span class="nav-number">2.5.</span> <span class="nav-text">搜索二叉树</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#应用场景-1"><span class="nav-number">2.5.1.</span> <span class="nav-text">应用场景</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#JavaScript-代码实现"><span class="nav-number">2.5.2.</span> <span class="nav-text">JavaScript 代码实现</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#自平衡二叉树"><span class="nav-number">2.6.</span> <span class="nav-text">自平衡二叉树</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#介绍-6"><span class="nav-number">2.6.1.</span> <span class="nav-text">介绍</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#概念"><span class="nav-number">2.6.1.1.</span> <span class="nav-text">概念</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#平衡因子"><span class="nav-number">2.6.1.2.</span> <span class="nav-text">平衡因子</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#自平衡二叉树-1"><span class="nav-number">2.6.1.3.</span> <span class="nav-text">自平衡二叉树</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#AVL树"><span class="nav-number">2.6.2.</span> <span class="nav-text">AVL树</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#介绍-7"><span class="nav-number">2.6.2.1.</span> <span class="nav-text">介绍</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#构建-AVL-树"><span class="nav-number">2.6.2.2.</span> <span class="nav-text">构建 AVL 树</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#LL-型"><span class="nav-number">2.6.2.2.1.</span> <span class="nav-text">LL 型</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#RR-型"><span class="nav-number">2.6.2.2.2.</span> <span class="nav-text">RR 型</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#LR-型"><span class="nav-number">2.6.2.2.3.</span> <span class="nav-text">LR 型</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#RL-型"><span class="nav-number">2.6.2.2.4.</span> <span class="nav-text">RL 型</span></a></li></ol></li><li class="nav-item nav-level-4"><a class="nav-link" href="#代码实现-1"><span class="nav-number">2.6.2.3.</span> <span class="nav-text">代码实现</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#平衡因子-1"><span class="nav-number">2.6.2.3.1.</span> <span class="nav-text">平衡因子</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#获取一个的高度"><span class="nav-number">2.6.2.3.2.</span> <span class="nav-text">获取一个的高度</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#添加四种旋转方法"><span class="nav-number">2.6.2.3.3.</span> <span class="nav-text">添加四种旋转方法</span></a><ol class="nav-child"><li class="nav-item nav-level-6"><a class="nav-link" href="#左旋"><span class="nav-number">2.6.2.3.3.1.</span> <span class="nav-text">左旋</span></a></li><li class="nav-item nav-level-6"><a class="nav-link" href="#右旋"><span class="nav-number">2.6.2.3.3.2.</span> <span class="nav-text">右旋</span></a></li><li class="nav-item nav-level-6"><a class="nav-link" href="#先左后右"><span class="nav-number">2.6.2.3.3.3.</span> <span class="nav-text">先左后右</span></a></li><li class="nav-item nav-level-6"><a class="nav-link" href="#先右后左"><span class="nav-number">2.6.2.3.3.4.</span> <span class="nav-text">先右后左</span></a></li><li class="nav-item nav-level-6"><a class="nav-link" href="#调整二叉树"><span class="nav-number">2.6.2.3.3.5.</span> <span class="nav-text">调整二叉树</span></a></li><li class="nav-item nav-level-6"><a class="nav-link" href="#在添加节点时检查并调整节点"><span class="nav-number">2.6.2.3.3.6.</span> <span class="nav-text">在添加节点时检查并调整节点</span></a></li></ol></li></ol></li><li class="nav-item nav-level-4"><a class="nav-link" href="#完整-AVL-Tree-代码"><span class="nav-number">2.6.2.4.</span> <span class="nav-text">完整 AVL Tree 代码</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#红黑树"><span class="nav-number">2.6.3.</span> <span class="nav-text">红黑树</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#AVL和红黑树的区别"><span class="nav-number">2.6.4.</span> <span class="nav-text">AVL和红黑树的区别</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#堆"><span class="nav-number">2.7.</span> <span class="nav-text">堆</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#介绍-8"><span class="nav-number">2.7.1.</span> <span class="nav-text">介绍</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#分类-1"><span class="nav-number">2.7.2.</span> <span class="nav-text">分类</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#存储"><span class="nav-number">2.7.3.</span> <span class="nav-text">存储</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#应用场景-2"><span class="nav-number">2.7.4.</span> <span class="nav-text">应用场景</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#操作"><span class="nav-number">2.7.5.</span> <span class="nav-text">操作</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#插入节点"><span class="nav-number">2.7.5.1.</span> <span class="nav-text">插入节点</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#删除节点"><span class="nav-number">2.7.5.2.</span> <span class="nav-text">删除节点</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#构建二叉堆"><span class="nav-number">2.7.5.3.</span> <span class="nav-text">构建二叉堆</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#代码实现-2"><span class="nav-number">2.7.6.</span> <span class="nav-text">代码实现</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#哈夫曼编码"><span class="nav-number">2.8.</span> <span class="nav-text">哈夫曼编码</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#几个概念"><span class="nav-number">2.8.1.</span> <span class="nav-text">几个概念</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#路径"><span class="nav-number">2.8.1.1.</span> <span class="nav-text">路径</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#路径长度"><span class="nav-number">2.8.1.2.</span> <span class="nav-text">路径长度</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#节点的带权路径长度"><span class="nav-number">2.8.1.3.</span> <span class="nav-text">节点的带权路径长度</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#树的带权路径长度"><span class="nav-number">2.8.1.4.</span> <span class="nav-text">树的带权路径长度</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#哈夫曼树"><span class="nav-number">2.8.1.5.</span> <span class="nav-text">哈夫曼树</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#哈夫曼编码-1"><span class="nav-number">2.8.1.6.</span> <span class="nav-text">哈夫曼编码</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#编码"><span class="nav-number">2.8.1.6.1.</span> <span class="nav-text">编码</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#解码"><span class="nav-number">2.8.1.6.2.</span> <span class="nav-text">解码</span></a></li></ol></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#构建哈夫曼树的流程"><span class="nav-number">2.8.2.</span> <span class="nav-text">构建哈夫曼树的流程</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#代码实现-构造哈夫曼树"><span class="nav-number">2.8.3.</span> <span class="nav-text">代码实现-构造哈夫曼树</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#图"><span class="nav-number">3.</span> <span class="nav-text">图</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#介绍-9"><span class="nav-number">3.1.</span> <span class="nav-text">介绍</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#术语"><span class="nav-number">3.1.1.</span> <span class="nav-text">术语</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#分类-2"><span class="nav-number">3.2.</span> <span class="nav-text">分类</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#有向图和无向图"><span class="nav-number">3.2.1.</span> <span class="nav-text">有向图和无向图</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#有权图"><span class="nav-number">3.2.2.</span> <span class="nav-text">有权图</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#连通性"><span class="nav-number">3.3.</span> <span class="nav-text">连通性</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#连通图"><span class="nav-number">3.3.1.</span> <span class="nav-text">连通图</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#强连通图"><span class="nav-number">3.3.2.</span> <span class="nav-text">强连通图</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#连通网"><span class="nav-number">3.3.3.</span> <span class="nav-text">连通网</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#生成树"><span class="nav-number">3.4.</span> <span class="nav-text">生成树</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#图的存储与操作"><span class="nav-number">3.5.</span> <span class="nav-text">图的存储与操作</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#图的存储"><span class="nav-number">3.5.1.</span> <span class="nav-text">图的存储</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#邻接矩阵"><span class="nav-number">3.5.1.1.</span> <span class="nav-text">邻接矩阵</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#邻接表"><span class="nav-number">3.5.1.2.</span> <span class="nav-text">邻接表</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#代码实现-3"><span class="nav-number">3.5.1.2.1.</span> <span class="nav-text">代码实现</span></a></li></ol></li><li class="nav-item nav-level-4"><a class="nav-link" href="#邻接多重表"><span class="nav-number">3.5.1.3.</span> <span class="nav-text">邻接多重表</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#逆邻接表"><span class="nav-number">3.5.1.4.</span> <span class="nav-text">逆邻接表</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#十字链表"><span class="nav-number">3.5.1.5.</span> <span class="nav-text">十字链表</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#图的遍历"><span class="nav-number">3.6.</span> <span class="nav-text">图的遍历</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#介绍-10"><span class="nav-number">3.6.1.</span> <span class="nav-text">介绍</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#广度优先遍历（BFS）"><span class="nav-number">3.6.2.</span> <span class="nav-text">广度优先遍历（BFS）</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#代码实现-4"><span class="nav-number">3.6.2.1.</span> <span class="nav-text">代码实现</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#深度优先遍历（DFS）"><span class="nav-number">3.6.3.</span> <span class="nav-text">深度优先遍历（DFS）</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#代码实现-5"><span class="nav-number">3.6.3.1.</span> <span class="nav-text">代码实现</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#最短路径"><span class="nav-number">3.7.</span> <span class="nav-text">最短路径</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#无向图"><span class="nav-number">3.7.1.</span> <span class="nav-text">无向图</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#有向图"><span class="nav-number">3.7.2.</span> <span class="nav-text">有向图</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#拓扑排序"><span class="nav-number">3.8.</span> <span class="nav-text">拓扑排序</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#有向无环图"><span class="nav-number">3.8.1.</span> <span class="nav-text">有向无环图</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#拓扑排序用途"><span class="nav-number">3.8.2.</span> <span class="nav-text">拓扑排序用途</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#实现思路"><span class="nav-number">3.8.3.</span> <span class="nav-text">实现思路</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#代码实现-6"><span class="nav-number">3.9.</span> <span class="nav-text">代码实现</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#创建类"><span class="nav-number">3.9.1.</span> <span class="nav-text">创建类</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#添加顶点"><span class="nav-number">3.9.1.1.</span> <span class="nav-text">添加顶点</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#添加边"><span class="nav-number">3.9.1.2.</span> <span class="nav-text">添加边</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#广度优先遍历（BFS）-1"><span class="nav-number">3.9.1.3.</span> <span class="nav-text">广度优先遍历（BFS）</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#深度优先遍历（DFS）-1"><span class="nav-number">3.9.1.4.</span> <span class="nav-text">深度优先遍历（DFS）</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#两个顶点之间的路径"><span class="nav-number">3.9.1.5.</span> <span class="nav-text">两个顶点之间的路径</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#在-BFS-时记录来路"><span class="nav-number">3.9.1.5.1.</span> <span class="nav-text">在 BFS 时记录来路</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#反向找两个顶点之间的路径"><span class="nav-number">3.9.1.5.2.</span> <span class="nav-text">反向找两个顶点之间的路径</span></a></li></ol></li></ol></li></ol></li></ol></li></ol></div></div></section><div class="back-to-top"><i class="fa fa-arrow-up"></i> <span id="scrollpercent"><span>0</span>%</span></div></div></aside></div></main><footer id="footer" class="footer"><div class="footer-inner"><div class="copyright">&copy; <span itemprop="copyrightYear">2020</span><span class="with-love"><i class="fa fa-user"></i></span> <span class="author" itemprop="copyrightHolder">宇宙特别帅</span></div></div></footer></div><script type="text/javascript">"[object Function]"!==Object.prototype.toString.call(window.Promise)&&(window.Promise=null)</script><script type="text/javascript" src="/lib/jquery/index.js?v=2.1.3"></script><script type="text/javascript" src="/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script><script type="text/javascript" src="/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script><script type="text/javascript" src="/lib/velocity/velocity.min.js?v=1.2.1"></script><script type="text/javascript" src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script><script type="text/javascript" src="/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script><script type="text/javascript" src="/lib/canvas-nest/canvas-nest.min.js"></script><script type="text/javascript" src="/js/src/utils.js?v=5.1.4"></script><script type="text/javascript" src="/js/src/motion.js?v=5.1.4"></script><script type="text/javascript" src="/js/src/affix.js?v=5.1.4"></script><script type="text/javascript" src="/js/src/schemes/pisces.js?v=5.1.4"></script><script type="text/javascript" src="/js/src/scrollspy.js?v=5.1.4"></script><script type="text/javascript" src="/js/src/post-details.js?v=5.1.4"></script><script type="text/javascript" src="/js/src/bootstrap.js?v=5.1.4"></script><script src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script><script src="//cdn.jsdelivr.net/npm/valine/dist/Valine.min.js"></script><script type="text/javascript">
    var GUEST = ['nick','mail','link'];
    var guest = 'nick,mail,link';
    guest = guest.split(',').filter(item=>{
      return GUEST.indexOf(item)>-1;
    });
    new Valine({
        el: '#comments' ,
        verify: false,
        notify: true,
        appId: '9DODHXKj6rr1cK4oO07iVBX3-gzGzoHsz',
        appKey: 'aJaxxns4VN5WV9nMimT9aSb1',
        placeholder: 'ヾﾉ≧∀≦)o 来呀！吐槽一番吧！',
        avatar:'mp',
        guest_info:guest,
        pageSize:'10' || 10,
    });
  </script><script type="text/javascript">
    // Popup Window;
    var isfetched = false;
    var isXml = true;
    // Search DB path;
    var search_path = "./public/search.xml";
    if (search_path.length === 0) {
      search_path = "search.xml";
    } else if (/json$/i.test(search_path)) {
      isXml = false;
    }
    var path = "/" + search_path;
    // monitor main search box;

    var onPopupClose = function (e) {
      $('.popup').hide();
      $('#local-search-input').val('');
      $('.search-result-list').remove();
      $('#no-result').remove();
      $(".local-search-pop-overlay").remove();
      $('body').css('overflow', '');
    }

    function proceedsearch() {
      $("body")
        .append('<div class="search-popup-overlay local-search-pop-overlay"></div>')
        .css('overflow', 'hidden');
      $('.search-popup-overlay').click(onPopupClose);
      $('.popup').toggle();
      var $localSearchInput = $('#local-search-input');
      $localSearchInput.attr("autocapitalize", "none");
      $localSearchInput.attr("autocorrect", "off");
      $localSearchInput.focus();
    }

    // search function;
    var searchFunc = function(path, search_id, content_id) {
      'use strict';

      // start loading animation
      $("body")
        .append('<div class="search-popup-overlay local-search-pop-overlay">' +
          '<div id="search-loading-icon">' +
          '<i class="fa fa-spinner fa-pulse fa-5x fa-fw"></i>' +
          '</div>' +
          '</div>')
        .css('overflow', 'hidden');
      $("#search-loading-icon").css('margin', '20% auto 0 auto').css('text-align', 'center');

      $.ajax({
        url: path,
        dataType: isXml ? "xml" : "json",
        async: true,
        success: function(res) {
          // get the contents from search data
          isfetched = true;
          $('.popup').detach().appendTo('.header-inner');
          var datas = isXml ? $("entry", res).map(function() {
            return {
              title: $("title", this).text(),
              content: $("content",this).text(),
              url: $("url" , this).text()
            };
          }).get() : res;
          var input = document.getElementById(search_id);
          var resultContent = document.getElementById(content_id);
          var inputEventFunction = function() {
            var searchText = input.value.trim().toLowerCase();
            var keywords = searchText.split(/[\s\-]+/);
            if (keywords.length > 1) {
              keywords.push(searchText);
            }
            var resultItems = [];
            if (searchText.length > 0) {
              // perform local searching
              datas.forEach(function(data) {
                var isMatch = false;
                var hitCount = 0;
                var searchTextCount = 0;
                var title = data.title.trim();
                var titleInLowerCase = title.toLowerCase();
                var content = data.content.trim().replace(/<[^>]+>/g,"");
                var contentInLowerCase = content.toLowerCase();
                var articleUrl = decodeURIComponent(data.url);
                var indexOfTitle = [];
                var indexOfContent = [];
                // only match articles with not empty titles
                if(title != '') {
                  keywords.forEach(function(keyword) {
                    function getIndexByWord(word, text, caseSensitive) {
                      var wordLen = word.length;
                      if (wordLen === 0) {
                        return [];
                      }
                      var startPosition = 0, position = [], index = [];
                      if (!caseSensitive) {
                        text = text.toLowerCase();
                        word = word.toLowerCase();
                      }
                      while ((position = text.indexOf(word, startPosition)) > -1) {
                        index.push({position: position, word: word});
                        startPosition = position + wordLen;
                      }
                      return index;
                    }

                    indexOfTitle = indexOfTitle.concat(getIndexByWord(keyword, titleInLowerCase, false));
                    indexOfContent = indexOfContent.concat(getIndexByWord(keyword, contentInLowerCase, false));
                  });
                  if (indexOfTitle.length > 0 || indexOfContent.length > 0) {
                    isMatch = true;
                    hitCount = indexOfTitle.length + indexOfContent.length;
                  }
                }

                // show search results

                if (isMatch) {
                  // sort index by position of keyword

                  [indexOfTitle, indexOfContent].forEach(function (index) {
                    index.sort(function (itemLeft, itemRight) {
                      if (itemRight.position !== itemLeft.position) {
                        return itemRight.position - itemLeft.position;
                      } else {
                        return itemLeft.word.length - itemRight.word.length;
                      }
                    });
                  });

                  // merge hits into slices

                  function mergeIntoSlice(text, start, end, index) {
                    var item = index[index.length - 1];
                    var position = item.position;
                    var word = item.word;
                    var hits = [];
                    var searchTextCountInSlice = 0;
                    while (position + word.length <= end && index.length != 0) {
                      if (word === searchText) {
                        searchTextCountInSlice++;
                      }
                      hits.push({position: position, length: word.length});
                      var wordEnd = position + word.length;

                      // move to next position of hit

                      index.pop();
                      while (index.length != 0) {
                        item = index[index.length - 1];
                        position = item.position;
                        word = item.word;
                        if (wordEnd > position) {
                          index.pop();
                        } else {
                          break;
                        }
                      }
                    }
                    searchTextCount += searchTextCountInSlice;
                    return {
                      hits: hits,
                      start: start,
                      end: end,
                      searchTextCount: searchTextCountInSlice
                    };
                  }

                  var slicesOfTitle = [];
                  if (indexOfTitle.length != 0) {
                    slicesOfTitle.push(mergeIntoSlice(title, 0, title.length, indexOfTitle));
                  }

                  var slicesOfContent = [];
                  while (indexOfContent.length != 0) {
                    var item = indexOfContent[indexOfContent.length - 1];
                    var position = item.position;
                    var word = item.word;
                    // cut out 100 characters
                    var start = position - 20;
                    var end = position + 80;
                    if(start < 0){
                      start = 0;
                    }
                    if (end < position + word.length) {
                      end = position + word.length;
                    }
                    if(end > content.length){
                      end = content.length;
                    }
                    slicesOfContent.push(mergeIntoSlice(content, start, end, indexOfContent));
                  }

                  // sort slices in content by search text's count and hits' count

                  slicesOfContent.sort(function (sliceLeft, sliceRight) {
                    if (sliceLeft.searchTextCount !== sliceRight.searchTextCount) {
                      return sliceRight.searchTextCount - sliceLeft.searchTextCount;
                    } else if (sliceLeft.hits.length !== sliceRight.hits.length) {
                      return sliceRight.hits.length - sliceLeft.hits.length;
                    } else {
                      return sliceLeft.start - sliceRight.start;
                    }
                  });

                  // select top N slices in content

                  var upperBound = parseInt('1');
                  if (upperBound >= 0) {
                    slicesOfContent = slicesOfContent.slice(0, upperBound);
                  }

                  // highlight title and content

                  function highlightKeyword(text, slice) {
                    var result = '';
                    var prevEnd = slice.start;
                    slice.hits.forEach(function (hit) {
                      result += text.substring(prevEnd, hit.position);
                      var end = hit.position + hit.length;
                      result += '<b class="search-keyword">' + text.substring(hit.position, end) + '</b>';
                      prevEnd = end;
                    });
                    result += text.substring(prevEnd, slice.end);
                    return result;
                  }

                  var resultItem = '';

                  if (slicesOfTitle.length != 0) {
                    resultItem += "<li><a href='" + articleUrl + "' class='search-result-title'>" + highlightKeyword(title, slicesOfTitle[0]) + "</a>";
                  } else {
                    resultItem += "<li><a href='" + articleUrl + "' class='search-result-title'>" + title + "</a>";
                  }

                  slicesOfContent.forEach(function (slice) {
                    resultItem += "<a href='" + articleUrl + "'>" +
                      "<p class=\"search-result\">" + highlightKeyword(content, slice) +
                      "...</p>" + "</a>";
                  });

                  resultItem += "</li>";
                  resultItems.push({
                    item: resultItem,
                    searchTextCount: searchTextCount,
                    hitCount: hitCount,
                    id: resultItems.length
                  });
                }
              })
            };
            if (keywords.length === 1 && keywords[0] === "") {
              resultContent.innerHTML = '<div id="no-result"><i class="fa fa-search fa-5x" /></div>'
            } else if (resultItems.length === 0) {
              resultContent.innerHTML = '<div id="no-result"><i class="fa fa-frown-o fa-5x" /></div>'
            } else {
              resultItems.sort(function (resultLeft, resultRight) {
                if (resultLeft.searchTextCount !== resultRight.searchTextCount) {
                  return resultRight.searchTextCount - resultLeft.searchTextCount;
                } else if (resultLeft.hitCount !== resultRight.hitCount) {
                  return resultRight.hitCount - resultLeft.hitCount;
                } else {
                  return resultRight.id - resultLeft.id;
                }
              });
              var searchResultList = '<ul class=\"search-result-list\">';
              resultItems.forEach(function (result) {
                searchResultList += result.item;
              })
              searchResultList += "</ul>";
              resultContent.innerHTML = searchResultList;
            }
          }

          if ('auto' === 'auto') {
            input.addEventListener('input', inputEventFunction);
          } else {
            $('.search-icon').click(inputEventFunction);
            input.addEventListener('keypress', function (event) {
              if (event.keyCode === 13) {
                inputEventFunction();
              }
            });
          }

          // remove loading animation
          $(".local-search-pop-overlay").remove();
          $('body').css('overflow', '');

          proceedsearch();
        }
      });
    }

    // handle and trigger popup window;
    $('.popup-trigger').click(function(e) {
      e.stopPropagation();
      if (isfetched === false) {
        searchFunc(path, 'local-search-input', 'local-search-result');
      } else {
        proceedsearch();
      };
    });

    $('.popup-btn-close').click(onPopupClose);
    $('.popup').click(function(e){
      e.stopPropagation();
    });
    $(document).on('keyup', function (event) {
      var shouldDismissSearchPopup = event.which === 27 &&
        $('.search-popup').is(':visible');
      if (shouldDismissSearchPopup) {
        onPopupClose();
      }
    });
  </script><script src="https://cdn1.lncld.net/static/js/av-core-mini-0.6.4.js"></script><script>AV.initialize("9DODHXKj6rr1cK4oO07iVBX3-gzGzoHsz","aJaxxns4VN5WV9nMimT9aSb1")</script><script>function showTime(e){var t=new AV.Query(e),c=[],u=$(".leancloud_visitors");u.each(function(){c.push($(this).attr("id").trim())}),t.containedIn("url",c),t.find().done(function(e){var t=".leancloud-visitors-count";if(0!==e.length){for(var n=0;n<e.length;n++){var o=e[n],i=o.get("url"),s=o.get("time"),r=document.getElementById(i);$(r).find(t).text(s)}for(n=0;n<c.length;n++){i=c[n],r=document.getElementById(i);var l=$(r).find(t);""==l.text()&&l.text(0)}}else u.find(t).text(0)}).fail(function(e,t){console.log("Error: "+t.code+" "+t.message)})}function addCount(i){var e=$(".leancloud_visitors"),s=e.attr("id").trim(),r=e.attr("data-flag-title").trim(),t=new AV.Query(i);t.equalTo("url",s),t.find({success:function(e){if(0<e.length){var t=e[0];t.fetchWhenSave(!0),t.increment("time"),t.save(null,{success:function(e){$(document.getElementById(s)).find(".leancloud-visitors-count").text(e.get("time"))},error:function(e,t){console.log("Failed to save Visitor num, with error message: "+t.message)}})}else{var n=new i,o=new AV.ACL;o.setPublicReadAccess(!0),o.setPublicWriteAccess(!0),n.setACL(o),n.set("title",r),n.set("url",s),n.set("time",1),n.save(null,{success:function(e){$(document.getElementById(s)).find(".leancloud-visitors-count").text(e.get("time"))},error:function(e,t){console.log("Failed to create")}})}},error:function(e){console.log("Error:"+e.code+" "+e.message)}})}$(function(){var e=AV.Object.extend("Counter");1==$(".leancloud_visitors").length?addCount(e):1<$(".post-title-link").length&&showTime(e)})</script><script src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.4/clipboard.min.js"></script><script type="text/javascript" src="/js/src/clipboard-use.js"></script></body></html>